i did some tests with k3d-surf about a year ago (http://thomasdiewald.com/blog/?p=573) , but i didnt think, this is possible with processing, its even cooler this way :)
//==========================================================
// sketch: PG_AlgebraicSurfaceViewer.pde - by Gerd Platl
//
// Surface Viewer using GLGraphics and Toxiclibs libraries.
//
// tested with:
// processing v1.5.1: http://processing.org/download/
// GLGraphics v1.0.0: http://glgraphics.sourceforge.net/
// ToxicLibs v0020: http://toxiclibs.org/
// https://bitbucket.org/postspectacular/toxiclibs/src
//
// v1.0 2011-12-15 inital release
// v1.1 2012-01-04 more surfaces
// v1.2 2012-02-10 more surfaces
// v1.3 2012-03-31 advanced color handling
// added mouse wheel handling
//
// note: because of using OpenGL it works only offline!
//
// See overview picture about surfaces realized in version 1.3...
// http://farm8.staticflickr.com/7064/6885477688_a34ddaa46e_b_d.jpg
//==========================================================
/*
mouse input:
left mouse button rotate
right mouse button rotation on/off
mouse wheel zoom in/out
key commands:
0 .. 99 select surface
cursor left/right scrolling speed
cursor up/down turn up/down
F1 toggle help & frames per second
F3,F4 +/- zoom in/out
blanc show next surface
backspace show previous surface
b random background color
c random material & light colors
m random material color
l random light 1 colors
L random light 2 colors
e toggle closed sides
o toggle rotate
r reset camera
s save picture file as Surface_<surfaceName>.png
t save surface mesh as binary STL file <surfaceName>.stl
w white material color
*/
import toxi.geom.*;
import toxi.geom.mesh.*;
import toxi.volume.*;
import codeanticode.glgraphics.*;
import processing.opengl.*;
import javax.media.opengl.*; // import for renderer
import java.awt.event.*; // import for mouse wheel event handling
int displayMode = 0;
int numberInputTimeout = 800; // milliSeconds
float shininess = 32;
boolean doRotate = true;
boolean closeSides = true;
boolean showHelp = false;
color bgColor = (128);
int dimX = 100;
int dimY = 100;
int dimZ = 100;
Vec3D volumeScale = new Vec3D(1, 1, 1).scaleSelf(320);
TriangleMesh mesh;
GLModel surfaceMesh; // used to store mesh on GPU
int numV = 0;
//-----------------------------------
void setup()
{
size(600, 600, GLConstants.GLGRAPHICS);
background(bgColor);
randomMaterialColors();
surface = new PSurface(initSurface);
frame.addMouseWheelListener(new MouseWheelInput()); // add mouse wheel listener
}
//-----------------------------------
void draw()
{
background(bgColor);
translate(width/2, height/2, 0);
rotateX(mouseY*0.01);
rotateY(mouseX*0.01);
CheckSelectionInput();
String msg = surface.index + ": " + surface.name;
switch (displayMode)
{ case 0: // display calculating...
println ("fc="+frameCount+ " " +surface.name);
msg += " calculating...";
displayMode++;
HandleCamera();
if (numV > 0) DoRendering();
break;
case 1: // calculate surface
CalculateSurface();
displayMode++;
text(msg,10,20);
break;
case 2: // draw surface
msg += " " + numV + " vertices";
HandleCamera();
DoRendering();
}
fill(255);
textMode(SCREEN);
text (msg,10,20);
if (showHelp)
text("keys: cursor,blanc,bs,+,-,b,c,l,o,e,r,s,t,w,0.."+(surfaces-1)+" fps=" + round(frameRate), 10, height-20);
}
//-----------------------------------
int selectionTime = 99999999;
int inputNumber = 0;
//-----------------------------------
void CheckSelectionInput()
{
if (millis() > selectionTime) // key input timeout?
{
println (">>> calculating surface " + inputNumber + ", please wait a moment ...");
SelectSurface (inputNumber); // 0..n: select surface function
inputNumber = 0;
selectionTime = 999999999;
}
}
//-----------------------------------
void numberPressed()
{
selectionTime = millis() + numberInputTimeout; // end of key input = current time + 1000 msec
inputNumber = inputNumber * 10 + keyCode-48;
}
//-----------------------------------
void keyPressed()
{
// if (debug) println (keyCode + " '" + key + "' ");
if ((key >= '0')
&& (key <= '9')) numberPressed(); // 0..n: select function
else if (keyCode == LEFT) speedX -= 0.1; // <- auto scroll to left
else if (keyCode == RIGHT) speedX += 0.1; // -> auto scroll to right
else if (keyCode == UP) rotY += 1.5; // W: scroll up
else if (keyCode == DOWN) rotY -= 1.5; // S: scroll down
else if (keyCode == 8) ChangeSurface (-1); // backspace
else if (keyCode == 32) ChangeSurface (+1); // blanc
else if ((keyCode == 114)
|| (key == '+')) zoomCamera (0.99); // F3, + zoom in
else if ((keyCode == 115)
|| (key == '-')) zoomCamera (1.01); // F4, - zoom out
else if (keyCode == 112) showHelp = !showHelp; // F1
else if (key == 'b') randomBackground();
else if (key == 'c') randomColors();
else if (key == 'm') randomMaterialColors();
else if (key == 'l') randomLight1Colors();
else if (key == 'L') randomLight2Colors();
else if (key == 'o') doRotate = !doRotate;
else if (key == 'e') { closeSides = !closeSides; displayMode = 0; }
else if (key == 'r') ResetCamera();
else if (key == 's') save("Surface_" + surface.name + ".png" ); // save picture file
else if (key == 't') mesh.saveAsSTL(sketchPath("Surface_" + surface.name+".stl")); // save mesh as STL file
else if (key == 'w') whiteColors();
else if (key == 'x') if (colorM2[3] == 1.0) colorM2[3] = 0.3; else colorM2[3] = 1.0;
else if (key == 'y') shininess++;
else if (key == 'z') shininess--;
}
//-----------------------------------
void mousePressed()
{
if (mouseButton == RIGHT) doRotate = !doRotate;
}
//===================================
// handle camera
//===================================
float rotX = 0; // vertical angle
float rotY = 100; // horizontal angle
float fov = 1.1; // vertical field-of-view angle (in radians)
float speedX = 0.2; // rotation speed
//-----------------------------------
void ResetCamera()
{
rotX = 0; // vertical angle
rotY = 100; // horizontal angle
fov = 1.1; // vertical field-of-view angle (in radians)
speedX = 0.2; // rotation speed
doRotate = true;
}
//-----------------------------------
void HandleCamera()
{
beginCamera();
if (fov < 0.1) fov = 0.1;
if (fov > 1.5) fov = 1.5;
perspective(fov, float(width)/height, 1, 800);
if (mousePressed)
{
if (mouseButton == LEFT)
{
rotX -= 0.5 * (mouseX - pmouseX);
rotY += 0.5 * (mouseY - pmouseY);
}
}
camera (0, rotY, 400, // eyeX, eyeY, eyeZ
0, 5, 0, // centerX, centerY, centerZ
0, -1, 0); // upX, upY, upZ
endCamera();
rotateY (rotX / 100.0); // left/right
if (doRotate) rotX += speedX;
}
//-----------------------------------
int zoomFrame = 0;
void zoomCamera(float factor)
{
fov *= factor;
if (frameCount != zoomFrame)
text ("zoom=" + nf(fov,0,2), 340,20);
zoomFrame = frameCount;
}
//-----------------------------------
// listen for MouseWheelEvent
//-----------------------------------
class MouseWheelInput implements MouseWheelListener
{ void mouseWheelMoved(MouseWheelEvent e)
{ fov *= 1.0 + 0.01 * e.getWheelRotation(); }
}
//===================================
// handle SURFACES
//===================================
PSurface surface; // handle surface functions
//-----------------------------------
void SelectSurface (int sno)
{
surface.SelectFunction(sno);
displayMode = 0;
}
//-----------------------------------
void ChangeSurface (int delta)
{
surface.SelectFunction(surface.index + delta);
displayMode = 0;
}
//-----------------------------------
void CalculateSurface()
{
PVector pos = new PVector ();
float NS=4.2;
VolumetricSpace volume = new VolumetricSpaceArray(volumeScale, dimX, dimY, dimZ);
// fill volume with values
for (int z=0; z<dimZ; z++)
{
pos.z = (z-dimZ/2)*NS;
for (int y=0; y<dimY; y++)
{
pos.y = (y-dimY/2)*NS;
for (int x=0; x<dimX; x++)
{
pos.x = (x-dimX/2)*NS;
//---------------------------------------------
volume.setVoxelAt(x, y, z, surface.Value(pos));
//---------------------------------------------
}
}
}
if (closeSides) volume.closeSides();
convertVolumeSpaceToMesh(volume);
}
//-----------------------------------
void convertVolumeSpaceToMesh(VolumetricSpace volume)
{
float ISO_THRESHOLD = 0.01;
// store in IsoSurface and compute surface mesh for the given threshold value
mesh = new TriangleMesh("iso");
IsoSurface surface = new HashIsoSurface(volume, 0.333333);
surface.computeSurfaceMesh(mesh, ISO_THRESHOLD);
// update lighting information
mesh.computeVertexNormals();
// get flattened vertex array
float[] verts = mesh.getMeshAsVertexArray();
// in the array each vertex has 4 entries (XYZ + 1 spacing)
numV = verts.length / 4;
float[] norms=mesh.getVertexNormalsAsArray();
surfaceMesh = new GLModel(this, numV, TRIANGLES, GLModel.STATIC);
surfaceMesh.beginUpdateVertices();
for (int i = 0; i < numV; i++)
surfaceMesh.updateVertex(i, verts[4 * i], verts[4 * i + 1], verts[4 * i + 2]);
surfaceMesh.endUpdateVertices();
surfaceMesh.initNormals();
surfaceMesh.beginUpdateNormals();
for (int i = 0; i < numV; i++)
surfaceMesh.updateNormal(i, norms[4 * i], norms[4 * i + 1], norms[4 * i + 2]);
surfaceMesh.endUpdateNormals();
// Setting the color of all vertices to white, but not directly used, see comments in the draw() method.
surfaceMesh.initColors();
surfaceMesh.beginUpdateColors();
for (int i = 0; i < numV; i++)
surfaceMesh.updateColor(i, 255, 255, 255);
surfaceMesh.endUpdateColors();
// Setting model shininess
println (shininess);
surfaceMesh.setShininess(shininess);
}
//===================================
// handle color
//===================================
float alpha = 1.0; // 0..1 transparency, 1.0 = opaque
float[] colorM1 = new float[] {0.3, 0.3, 0.3, alpha};
float[] colorM2 = new float[] {0.5, 0.8, 0.6, alpha};
float[] colorL0d = new float[] {1.0, 1.0, 1.0, 0.1};
float[] colorL0s = new float[] {1.0, 1.0, 1.0, 0.1};
float[] colorL1d = new float[] {0.9, 0.3, 0.5, 0.1};
float[] colorL1s = new float[] {0.8, 0.8, 0.6, 0.1};
float[] light1pos = new float[] {-100, 600, 2000, 0};
float[] light2pos = new float[] {1000, -600, -2000, 0};
//-----------------------------------
void randomBackground()
{
bgColor = color(100+random(55), 100+random(55), 100+random(55));
}
//-----------------------------------
void randomColor(float[] rColor)
{
rColor[0] = random(1.0); // R
rColor[1] = random(1.0); // G
rColor[2] = random(1.0); // B
// rColor[3] = random(1.0); // alpha
println (nf(rColor[0],0,2) + " " + nf(rColor[1],0,2) + " " + nf(rColor[2],0,2));
}
//-----------------------------------
void whiteColors()
{
colorM2 = new float[] {1, 1, 1, alpha};
}
//-----------------------------------
void randomMaterialColors()
{
println ("random material colors");
randomColor (colorM1);
randomColor (colorM2);
}
//-----------------------------------
void randomLight1Colors()
{
println ("random light-1 colors");
randomColor (colorL0d);
randomColor (colorL0s);
}
//-----------------------------------
void randomLight2Colors()
{
println ("random light-2 colors");
randomColor (colorL1d);
randomColor (colorL1s);
}
//-----------------------------------
void randomColors()
{
randomMaterialColors();
randomLight1Colors();
randomLight2Colors();
}
//===================================
// do rendering
//===================================
void DoRendering()
{
// need to switch to pure OpenGL mode first
GLGraphics renderer = (GLGraphics)g;
renderer.beginGL();
renderer.gl.glEnable(GL.GL_LIGHTING);
// Disabling color tracking, so the lighting is determined using the colors
// set only with glMaterialfv()
// renderer.gl.glDisable(GL.GL_COLOR_MATERIAL);
// Enabling color tracking for the specular component, this means that the
// specular component to calculate lighting will obtained from the colors of the model.
// This tutorial is quite good to clarify issues regarding lighting in OpenGL:
// http://www.sjbaker.org/steve/omniv/opengl_lighting.html
renderer.gl.glEnable(GL.GL_COLOR_MATERIAL);
// renderer.gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR);
renderer.gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, colorM1, 0);
renderer.gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, colorM2, 0);
renderer.gl.glEnable(GL.GL_LIGHT0);
renderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light1pos, 0);
renderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, colorL0d, 0);
renderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, colorL0s, 0);
renderer.gl.glEnable(GL.GL_LIGHT1);
renderer.gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, light2pos, 0);
renderer.gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, colorL1d, 0);
renderer.gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, colorL1s, 0);
renderer.model(surfaceMesh); // render surface triangle mesh
renderer.endGL(); // back to processing
}
//==========================================================
// sketch: SurfaceFunctions.pde
// implement class PSurface
// and some examples of algebraic surface functions
// v1.0 2011-12-15 inital release
// v1.1 2012-01-04 more surfaces
// v1.2 2012-02-10 more surfaces
// v1.3 2012-03-31 added more surfaces:
// PG_C16CubeValue, BorromeanRings1, PG_DoubleHelix_1,
// BarthsSextik1, BarthsDecic
//
// The default function space in x, y and z direction
// is best viewed within -200 .. +200.
// Positive function values means you are inside the 3d-shape.
//
// How to add a new surface function:
// - note: replace <XXX> to new surface name
// - add new <XXX>Value() to 'functions' list
// - create class <XXX>Value as copy of class XxxValue
// - implement function <XXX>Value
// - use PVector.mult(pos, <scaleFactor>); for scaling
//
//==========================================================
int initSurface = 29; // sketch starting index of surface
//----------------------------------------------------------
// function definition: calculate value at given 3d position
//----------------------------------------------------------
interface SurfaceFunction
{
String getName();
float getValue (PVector pos);
}
//----------------------------------------------------------
// set list of all surface functions
//----------------------------------------------------------
SurfaceFunction[] functions = new SurfaceFunction[]
{
new PlaneValue(),
new CylinderValue(),
new SphereValue(),
new QSphereValue(),
new TorusValue(),
new BlobValue(),
new Chmutov2Value(),
new PG_C8CubeValue(),
new PG_C16CubeValue(),
new TetrahedralValue(),
new McMullenValue(),
new HeartValue(),
new Bretzel2Value(),
new Bretzel6Value(),
new SchwartzValue(),
new GyroidValue(),
new SteinerSurface1(),
new BorromeanRings1(),
new SchwartzRing_01(),
new PG_WireCube_2(),
new PG_RippleCube_2(),
new PG_Alienship_2(),
new PG_Tuetue_1(),
new PG_Icosa_4(),
new PG_Meteor_898989(),
new PG_TwistedTorus_3(),
new PG_DoubleHelix_1(),
new PG_Isolator_1(),
new PG_Beasty_1(),
new BarthsSextik(),
new BarthsDecic(),
// fractals
new Mandelbulb_8Power(),
new Julia3d()
};
int surfaces = functions.length; // number of surfaces
//==========================================================
// define class PSurface to handle surfaces
//==========================================================
class PSurface
{
int index; // current function index
String name; // current surface name
SurfaceFunction sFunc; // current surface function
// set surface function by index
public PSurface (int functionIndex)
{
SelectFunction (functionIndex);
}
// select surface function by index
void SelectFunction(int functionIndex)
{
this.index = (functionIndex + surfaces) % surfaces;
this.name = functions[index].getName();
this.sFunc = functions[index]; // set function call
}
// get algebraic surface value at given position
float Value(PVector pos)
{ //println ("getValue: " + sfunc.getValue(pos));
return sFunc.getValue(pos);
}
}
//==========================================================
// define algebraic surface functions
//==========================================================
//PVector v1 = new PVector ();
//---------------------------------------------------------
// Plane: z^2 = 0
//---------------------------------------------------------
class PlaneValue implements SurfaceFunction
{
String getName() { return "Plane"; }
float getValue(PVector pos)
{
return 10-100 * sq(pos.z);
}
}
//----------------------------------------------------------
// Cylinder: y^2+z^2 = r^2 r=radius
//----------------------------------------------------------
class CylinderValue implements SurfaceFunction
{
String getName() { return "Cylinder"; }
float getValue(PVector pos)
{
return 4000 - (sq(pos.z) + sq(pos.y));
}
}
//----------------------------------------------------------
// Sphere: x^2+y^2+z^2 = r^2 r=radius
//----------------------------------------------------------
class SphereValue implements SurfaceFunction
{
String getName() { return "Sphere"; }
public float getValue(PVector pos)
{
return 40000 - (sq(pos.x) + sq(pos.y) + sq(pos.z)) ;
}
}
//----------------------------------------------------------
// QSphere: x^8+y^8+z^8 = r^8 r=radius
//----------------------------------------------------------
class QSphereValue implements SurfaceFunction
{
String getName() { return "QSphere"; }
public float getValue(PVector pos)
{
return 25.0E16 - (pow(pos.x,8) + pow(pos.y,8) + pow(pos.z,8)) ;
}
}
//----------------------------------------------------------
// Torus: rr^2 - z^2 - sqr(sqrt(x^2+y^2)-tr) = 0
//----------------------------------------------------------
float tr = 180; // torus radius
float rr = 20*20; // ring radius ^ 2
class TorusValue implements SurfaceFunction
{
String getName() { return "Torus"; }
public float getValue(PVector pos)
{
return rr - sq(pos.z) - sq (sqrt(sq(pos.x) + sq(pos.y)) - tr);
}
}
//----------------------------------------------------------
// Implicit Blob Surface: x^2+y^2+z^2 +cos(4*x) +cos(4*y) +cos(4*z)+k
//----------------------------------------------------------
class BlobValue implements SurfaceFunction
{
String getName() { return "Blob"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.006);
return 100 - 1000 * (v1.dot(v1) +cos(4*v1.x) +cos(4*v1.y) +cos(4*v1.z));
}
}
//----------------------------------------------------------
// Chmutov-2 Surface:
// 1-(x^2*(3-4*x^2)^2
// + y^2*(3-4*y^2)^2
// + z^2*(3-4*z^2)^2)
// http://mathworld.wolfram.com/ChmutovSurface.html
//----------------------------------------------------------
class Chmutov2Value implements SurfaceFunction
{
String getName() { return "Chmutov-2"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.006);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
return 1.01-(x2*sq(3-4*x2)+y2*sq(3-4*y2)+z2*sq(3-4*z2));
}
}
//----------------------------------------------------------
// PG_C8Cube
// 1 -(27*x*x*(4*x*x*(x*x-1)+1)-1)^2
// -(27*y*y*(4*y*y*(y*y-1)+1)-1)^2
// -(27*z*z*(4*z*z*(z*z-1)+1)-1)^2
//----------------------------------------------------------
class PG_C8CubeValue implements SurfaceFunction
{
String getName() { return "PG_C8Cube"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0055);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
return 1.02 -(sq(8*x2*(x2-1) + 1)
+sq(8*y2*(y2-1) + 1)
+sq(8*z2*(z2-1) + 1));
}
}
//----------------------------------------------------------
// PG_C16Cube
// 1 -(27*x*x*(4*x*x*(x*x-1)+1)-1)^2
// -(27*y*y*(4*y*y*(y*y-1)+1)-1)^2
// -(27*z*z*(4*z*z*(z*z-1)+1)-1)^2
//----------------------------------------------------------
class PG_C16CubeValue implements SurfaceFunction
{
String getName() { return "PG_C16Cube"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0055);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
return 1.02 -sq(27*x2*(4*x2*(x2-1)+1)-1)
-sq(27*y2*(4*y2*(y2-1)+1)-1)
-sq(27*z2*(4*z2*(z2-1)+1)-1);
}
}
//----------------------------------------------------------
// Tetrahedral Surface:
// http://www.javaview.de/services/algebraic/index.html
// (x^2 + y^2 + z^2)^2 + 8*x*y*z - 10*(x^2 + y^2 + z^2) + 25=0
//----------------------------------------------------------
class TetrahedralValue implements SurfaceFunction
{
String getName() { return "Tetrahedral"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.014);
float f2 = v1.dot(v1); // f2 = (x^2 + y^2 + z^2)
return -(f2*f2 + 8 * v1.x * v1.y * v1.z - 10*f2 + 25.0);
}
}
//----------------------------------------------------------
// Implicit McMullenK3
// (1 + x*x) * (1 + y*y) * (1 + z*z) + 8 * x * y * z - k
// http://local.wasp.uwa.edu.au/~pbourke/geometry/mullen/
//----------------------------------------------------------
class McMullenValue implements SurfaceFunction
{
String getName() { return "McMullen"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0082);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
return -100 * ((1+x2) * (1+y2) * (1+z2) + 8 * v1.x * v1.y * v1.z - 1.4);
}
}
//----------------------------------------------------------
// Heart
// (2*x^2+y^2+z^2-1)^3 -0.1*x^2*z^3 - y^2*z^3
//----------------------------------------------------------
class HeartValue implements SurfaceFunction
{
String getName() { return "Heart"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0062);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
float y3 = v1.y*y2;
return -400 * (pow(2*z2 +x2 + y2-1, 3) -0.1*z2*y3 -x2*y3);
}
}
//----------------------------------------------------------
// Implicit Bretzel2
// ((x^2 +y^2)^2 - x^2 + y^2)^2 + z^2 - 0.02;
// http://www.lama.univ-savoie.fr/~simon/Genus2.jpg
// http://virtualmathmuseum.org/Surface/bretzel2/bretzel2.html
//----------------------------------------------------------
class Bretzel2Value implements SurfaceFunction
{
String getName() { return "Bretzel2"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0052);
float x2 = v1.x*v1.x;
float y2 = v1.y*v1.y;
float z2 = v1.z*v1.z;
return -400 * (sq(x2*x2 +y2*y2 -x2 +y2) +z2 -0.01);
}
}
//----------------------------------------------------------
// Isosurface: PG_Bretzel6
// (x*x*x*x +y*y*y*y -x*x +y*y)^2 +z*z -0.01)
// *(z*z*z*z +y*y*y*y -y*y +z*z)^2 +x*x -0.01)
// *(x*x*x*x +z*z*z*z -z*z +x*x)^2 +y*y -0.01)-0.00001
//----------------------------------------------------------
class Bretzel6Value implements SurfaceFunction
{
String getName() { return "Bretzel6"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0052);
float x2 = v1.x*v1.x;
float x4 = x2*x2;
float y2 = v1.y*v1.y;
float y4 = y2*y2;
float z2 = v1.z*v1.z;
float z4 = z2*z2;
return -300 * ((sq(x4 +y4 -x2 +y2) +z2 -0.01)
*(sq(z4 +y4 -y2 +z2) +x2 -0.01)
*(sq(x4 +z4 -z2 +x2) +y2 -0.01)
-0.0037);
}
}
//----------------------------------------------------------
class SchwartzValue implements SurfaceFunction
{
String getName() { return "Schwartz"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.062);
return 0.1 - (cos(v1.x) + cos(v1.y) + cos(v1.z));
}
}
//----------------------------------------------------------
class GyroidValue implements SurfaceFunction
{
String getName() { return "Gyroid"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.04);
return abs (cos(v1.x)*sin(v1.z)
+ cos(v1.y)*sin(v1.x)
+ cos(v1.z)*sin(v1.y)) - 1.0;
}
}
//----------------------------------------------------------
// Isosurface: SteinerSurface1 9/2007
//----------------------------------------------------------
class SteinerSurface1 implements SurfaceFunction
{
String getName() { return "SteinerSurface1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.005);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return 0.01 -2*x*y*z -sq(x*y) -sq(x*z) -sq(y*z);
}
}
//----------------------------------------------------------
// Isosurface: PG_SteinerSurface_1 9/2007
//----------------------------------------------------------
class BorromeanRings1 implements SurfaceFunction
{
String getName() { return "BorromeanRings1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.032);
float x = sq(v1.x);
float y = sq(v1.y);
float z = sq(v1.z);
return -(sq(0.1*x+y+z+2) -9*(0.1*x+y))
*(sq(0.1*z+x+y+2) -9*(0.1*z+x))
*(sq(0.1*y+z+x+2) -9*(0.1*y+z));
}
}
//----------------------------------------------------------
// http://k3dsurf.s4.bizhat.com/k3dsurf-ftopic30-0.html
//----------------------------------------------------------
class SchwartzRing_01 implements SurfaceFunction
{
String getName() { return "SchwartzRing_01"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.013);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return -((cos(x)+ cos(y) + cos(z))
*((cos(x + sin(x)/4)
+ cos(y + sin(y)/4)
+ cos(z + sin(z)/4)))
+0.06*sq(sin((y*y)) +sin((x*x)) +sin((z*z))));
}
}
//----------------------------------------------------------
class PG_WireCube_2 implements SurfaceFunction
{
String getName() { return "PG_WireCube_2"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0055);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return pow(x,16) + pow(y,16) + pow(z,16)
-(pow(x,18) + pow(y,18) + pow(z,18))
-0.06;
}
}
//----------------------------------------------------------
// http://www.flickr.com/photos/flisp3d/4776634565/
//----------------------------------------------------------
class PG_RippleCube_2 implements SurfaceFunction
{
String getName() { return "PG_RippleCube_2"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0056);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return 0.05 * (0.5 - sq(1-(pow(x,16) + pow(y,16) + pow(z,16))))
-( sq(2*x) * sq(2*y) * sq(2*z)
* sq(x+y) * sq(z+y) * sq(x+z)
* sq(x-z) * sq(x-y) * sq(2*y-2*z));
}
}
//----------------------------------------------------------
// http://k3dsurf.s4.bizhat.com/k3dsurf-ftopic30-0.html
//----------------------------------------------------------
class PG_Alienship_2 implements SurfaceFunction
{
String getName() { return "PG_Alienship_2"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.036);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return (cos(y) +2*cos(x)*cos(z)
-(cos(x) + cos(y) + cos(z))
*((cos(x + sin(x)/2.2)
+cos(y + sin(y)/2.2)
+cos(z + sin(z)/2.2)))
-0.0008*(sq(x*x)+sq(y*y)+sq(z*z)));
}
}
//----------------------------------------------------------
class PG_Icosa_4 implements SurfaceFunction
{
String getName() { return "PG_Icosa_4"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.033);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float f1 = (1+sqrt(5))/2;
return 1 - ( cos(x+f1*y) + cos(x-f1*y)
+ cos(y+f1*z) + cos(y-f1*z)
+ cos(z-f1*x) + cos(z+f1*x))*33333
/ (x*x+y*y+z*z)
- sq(x*x+y*y+z*z);
}
}
//----------------------------------------------------------
// http://k3dsurf.s4.bizhat.com/k3dsurf-ftopic30-15.html
//----------------------------------------------------------
class PG_Tuetue_1 implements SurfaceFunction
{
String getName() { return "PG_Tuetue_1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.014);
float x = v1.x;
float y = v1.y;
float z = v1.z;
return -0.07*(pow(x,4) + pow(y,4) + pow(z,4) - 22)
+1.05*(sin(x*y) + sin(y*z) + sin(z*x));
}
}
//----------------------------------------------------------
class PG_Meteor_898989 implements SurfaceFunction
{
String getName() { return "PG_Meteor_898989"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.01);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float f1 = cos(4*x)*sin(4*y) +cos(4*y)*sin(4*z) +cos(4*z)*sin(4*x);
float f2 = cos(8*x)*cos(9*y) +cos(8*y)*cos(9*z) +cos(8*z)*cos(9*x);
float f3 = cos(x) +cos(y) +cos(z);
float f4 = cos(x+sin(x)/4) +cos(y+sin(y)/4) +cos(z+sin(z)/4);
return f1 + 0.5*f2 + f3*f4 -4;
}
}
//----------------------------------------------------------
class PG_TwistedTorus_3 implements SurfaceFunction
{
String getName() { return "PG_TwistedTorus_3"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.03);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float f1 = sqrt(x*x+y*y)-5;
float f2 = atan2(x,y);
return -1.0 * ( pow(f1*cos(f2) - z*sin(f2), 8)
+pow(f1*sin(f2) + z*cos(f2), 8) - 1
);
}
}
//----------------------------------------------------------
// 1.0 - (sqrt(x^2+y^2)-5)^2
// - (atan((z*cos(y)-x*sin(y))/(x*cos(y)+z*sin(y))))^2
//----------------------------------------------------------
class PG_DoubleHelix_1 implements SurfaceFunction
{
String getName() { return "PG_DoubleHelix_1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.035);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float sinY = sin(y);
float cosY = cos(y);
return 1.0 - sq(sqrt(x*x+z*z) - 5.0)
- sq(atan( (z*cosY - x*sinY) / (x*cosY + z*sinY)));
}
}
//----------------------------------------------------------
class PG_Isolator_1 implements SurfaceFunction
{
String getName() { return "PG_Isolator_1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.01);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float xyz = x*y*z;
return 1 - (x*x+3)*(y*y+3)*(z*z+3) + 33*(xyz+0.96) + sin(xyz*11);
}
}
//----------------------------------------------------------
class PG_Beasty_1 implements SurfaceFunction
{
String getName() { return "PG_Beasty_1"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.03);
float x = sq(v1.x);
float y = sq(v1.y);
float z = sq(v1.z);
return 4*x*y*(1-z) - sq(x+y-z) +222;
}
}
//----------------------------------------------------------
// Barths Sextik Surface
// http://cage.ugent.be/~hs/barth/barth.html
// 4*(k*x^2-y^2)*(k*y^2-z^2)*(k*z^2-x^2)
// - (1+2j)*(x^2+y^2+z^2-1)^2 = 0
//----------------------------------------------------------
class BarthsSextik implements SurfaceFunction
{
float j = (1+sqrt(5))/2;
float k = sq(j);
String getName() { return "BarthsSextik"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.01);
float x2 = sq(v1.x);
float y2 = sq(v1.y);
float z2 = sq(v1.z);
return 4*(k*x2-y2)
*(k*y2-z2)
*(k*z2-x2)
-(1+2*j) * sq(x2+y2+z2-1);
}
}
//----------------------------------------------------------
// Barths Decic Surface
// http://cage.ugent.be/~hs/barth/barth.html
// 8*(x2-k*y2)*(y2-k*z2)*(z2-k*x2)
// * (x4+y4+z4 -2*x2*y2 -2*y2*z2 - 2*z2*x2)
// + (3+5*j)*(x2+y2+z2-1)^2 * (x2+y2+z2-(2-j))^2 = 0
//
//----------------------------------------------------------
class BarthsDecic implements SurfaceFunction
{
float j = (1+sqrt(5))/2;
float k = sq(j*j);
String getName() { return "BarthsDecic"; }
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.011);
float x2 = sq(v1.x);
float y2 = sq(v1.y);
float z2 = sq(v1.z);
return -8*(x2-k*y2)*(y2-k*z2)*(z2-k*x2)
*(x2*x2+y2*y2+z2*z2 -2*x2*y2 -2*y2*z2 - 2*z2*x2)
- (3+5*j)*sq(x2+y2+z2-1) * sq(x2+y2+z2-(2-j));
}
}
//---------------------------------------------------------
// Mandelbulb Surface
// http://www.skytopia.com/project/fractal/2mandelbulb.html#formula
//---------------------------------------------------------
float cosX = 0.0;
float sinX = 0.0;
class Mandelbulb_8Power implements SurfaceFunction
{
String getName() { return "Mandelbulb_8Power"; }
int iterations = 4;
public float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0052);
float x = v1.x;
float y = v1.z;
float z = v1.y;
float sinT8, cosT8;
float r = 0.0;
for (int ni=0; ni < iterations; ni++)
{
// convert (x,y,z) to polar coordinates (r, th, ph)
float w2 = x*x + y*y;
float w = sqrt(w2);
float r2 = w2 + z*z;
r = sqrt(r2);
if (r >= 2.0) break; //===>
// raise (r, th, ph) to the 8th power
MandelBulb_8th (w, z, r); sinT8 = sinX; cosT8 = cosX;
MandelBulb_8th (y, x, w);
//(r, th, ph) <- c + (r, th, ph)^8
float r8 = r2 * r2 * r2 * r2;
x = v1.x + r8 * sinT8 * cosX;
y = v1.z + r8 * sinT8 * sinX;
z = v1.y + r8 * cosT8;
}
return 2.0 - r;
}
}
//---------------------------------------------------------
// Compute sin(8t) & cos(8t) given r*sin(t), r*cos(t) & r
//---------------------------------------------------------
void MandelBulb_8th (float ps, float pc, float r)
{
sinX = ps;
cosX = pc;
if (r > 0.000001)
{
float s = ps / r;
float c = pc / r;
// iterate formula for sin(2t) & cos(2t) 3 times to get sin(8t) & cos(8t)
float t = 2.0*s*c; c = c*c - s*s; s = t;
t = 2.0*s*c; c = c*c - s*s; s = t;
t = 2.0*s*c; c = c*c - s*s; s = t;
sinX = s;
cosX = c;
}
}
//----------------------------------------------------------
// http://www.fractalforums.com/3d-fractal-generation/true-3d-mandlebrot-type-fractal/msg8470/#msg8470
//----------------------------------------------------------
class Julia3d implements SurfaceFunction
{
String getName() { return "Julia3d"; }
private float maxRadius = 1000.0;
float getValue(PVector pos)
{
PVector v1 = PVector.mult(pos, 0.0055);
float x = v1.x;
float y = v1.y;
float z = v1.z;
float radius = 0.0;
float ny,nx,nz;
for(int ni = 0; ni < 45; ni++)
{
nx = x*x - z*z - 0.27; nz = 2*x*z; // variant 1
// nx = x*x-z*z-0.285; nz = 2*x*z-0.1; // variant 2
// nx = x*x-z*z-0.27; nz = 3*x*z; // variant 3
// nx = x*x-z*z-0.25; nz = 16*x*y*z-0.2; // variant 4
ny = y;
x = nz;
y = -nx;
z = -ny;
radius = x*x + y*y + z*z;
if (radius > maxRadius) break;
}
return maxRadius - radius;
}
}
//----------------------------------------------------------
// use this draft to create your surface function...
//----------------------------------------------------------
class XxxValue implements SurfaceFunction
{
String getName() { return "???surfacename???"; }
public float getValue(PVector pos)
{
return 123.456;
}
}
Surface Viewer v1.3 (Mar2012) using GLGraphics and Toxiclibs libraries.
Because of using OpenGL it works only offline!
-- mouse input --
left mouse button rotate
right mouse button rotation on/off
mouse wheel zoom in/out
-- key commands --
0 .. 99 select surface
cursor left/right scrolling speed
cursor up/down turn up/down
F1 toggle help & frames per second
F3,F4 +/- zoom in/out
blanc show next surface
backspace show previous surface
r reset camera
s save picture file as Surface_<surfaceName>.png
for more commands see source...
Gerd Platl
Gerd Platl
Gerd Platl