Last active
November 27, 2018 09:46
-
-
Save KrabCode/733c2b4fdd636378a50283303975d72c to your computer and use it in GitHub Desktop.
Tessellated spheres source in IntelliJ IDEA - to run this in the vanilla Processing IDE just remove everything that mentions MainApp including the "class MainApp extends PApplet" part and you're golden - also you'll need the PostFX and PeasyCam libraries found in Tools -> Add tool.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ch.bildspur.postfx.builder.PostFX; | |
import peasy.PeasyCam; | |
import processing.core.PApplet; | |
import processing.core.PShape; | |
import processing.core.PVector; | |
import processing.opengl.PShader; | |
import java.util.ArrayList; | |
public class MainApp extends PApplet { | |
PeasyCam cam; | |
PostFX fx; | |
private ArrayList<Particle> particles = new ArrayList<Particle>(); | |
private PShape[] tesselatedSpheresIndexedByDetailLevel; | |
private ArrayList<PShape> rings = new ArrayList<PShape>(); | |
private float sinTime = 0; | |
private float linearTime = 0; | |
private float linearTimeAtCaptureStart = 0; | |
private float expectedLinearTimeAtCaptureEnd = 0; | |
private float rot = 0; | |
private float rotSpd = 0; | |
private int backgroundColorA; | |
private int backgroundColorB; | |
private PVector center; | |
private float screen; | |
private float sunRadius; | |
private int maxSphereDetail = 3; | |
private int baseShapeRadius = 50; | |
private int totalFramesToAnimate = 300; | |
private float rotationMaxSpeed = .8f; | |
private boolean onPC = true; | |
private boolean capturingLoopRightNow = false; | |
private int capturingLoopStartFrame=0; | |
private PShader phong; | |
public static void main(String[] args) { | |
PApplet.main("MainApp"); | |
} | |
public void settings() { | |
size(1000,1000,P3D); | |
smooth(8); | |
} | |
public void keyPressed() { | |
if (key=='k') { | |
capturingLoopStartFrame = frameCount; | |
linearTimeAtCaptureStart = linearTime; | |
expectedLinearTimeAtCaptureEnd = (frameCount+totalFramesToAnimate)*TWO_PI/totalFramesToAnimate; | |
capturingLoopRightNow = true; | |
} | |
} | |
public void setup() { | |
frameRate(30); | |
//the order of 1) cam and 2) fx is important | |
cam = new PeasyCam(this, 600); | |
fx = new PostFX(this); | |
phong = loadShader("PhongFrag.glsl", "PhongVert.glsl"); | |
colorMode(RGB, 255, 255, 255, 100); | |
ellipseMode(CENTER); | |
rectMode(CENTER); | |
backgroundColorA = color(30, 0, 0); | |
backgroundColorB = color(0, 0, 30); | |
screen = min(width, height); | |
center = new PVector(width * .5f, height * .5f); | |
tesselatedSpheresIndexedByDetailLevel = new PShape[maxSphereDetail]; | |
for (int i = 1; i < maxSphereDetail; i++) { | |
tesselatedSpheresIndexedByDetailLevel[i] = createSphere(baseShapeRadius, i); | |
} | |
//size of the sun in the middle for scale | |
sunRadius = (screen * .05f) / 2f; | |
//spheres of rising size forming main ring around the sun | |
particles.addAll(generateParticleCloud( | |
500, | |
screen * .05f, | |
screen * .225f, | |
screen * .005f, | |
screen * .02f, | |
radians(20), | |
"sphere" | |
)); | |
//tiny boxes huge cloud | |
particles.addAll(generateParticleCloud( | |
300, | |
screen * .1f, | |
screen * .5f, | |
screen * .003f, | |
screen * .0031f, | |
TWO_PI*4, | |
"box" | |
)); | |
//obelisks rotating on the margins | |
particles.addAll(generateParticleCloud( | |
12, | |
screen * .3f, | |
screen * .31f, | |
screen * .05f, | |
screen * .05f, | |
0, | |
"box", "obelisk", "deterministicRotPos", "noLocalRot" | |
)); | |
String[] unusedFlags = {"restrictedYDeviation"}; | |
} | |
public void draw() { | |
sinTime = sin(frameCount * TWO_PI / totalFramesToAnimate); | |
linearTime = frameCount * TWO_PI / totalFramesToAnimate; | |
hint(DISABLE_DEPTH_TEST); | |
cam.beginHUD(); | |
backgroundGradient(); | |
cam.endHUD(); | |
hint(ENABLE_DEPTH_TEST); | |
// translate(center.x, center.y, screen / 5.4f); | |
rotateX(PI * .35f); | |
rotateZ(rot + 0.244346095f); | |
lightSpecular(255, 255, 255); | |
pointLight(255, 255, 255, 0, 0, 0); | |
shininess(10); | |
for (Particle particle : particles) { | |
particle.draw(); | |
} | |
noLights(); | |
if (onPC) { | |
resetShader(); | |
} | |
fill(0); | |
stroke(150); | |
strokeWeight(2); | |
rotateY(linearTime); | |
shape(tesselatedSpheresIndexedByDetailLevel[2]); | |
rot += rotSpd; | |
rotSpd *= .98; | |
cam.beginHUD(); | |
float bloomIntensity = 6.759259f; | |
fx.render().bloom(0, floor(bloomIntensity), bloomIntensity) | |
.chromaticAberration() | |
.compose(); | |
cam.endHUD(); | |
if(capturingLoopRightNow && frameCount-capturingLoopStartFrame <= totalFramesToAnimate){ | |
saveFrame("test10//##.png"); | |
println(frameCount-capturingLoopStartFrame + "/" +totalFramesToAnimate); | |
} | |
} | |
private ArrayList<Particle> generateParticleCloud(float count, float startR, float endR, float minPSize, float maxPSize, float deviation, String... flags) { | |
ArrayList<Particle> cloud = new ArrayList<Particle>(); | |
for (int i = 0; i < count; i++) { | |
float r = map(i, 0, count, startR, endR); | |
float a = random(TWO_PI); | |
if (contains("deterministicRotPos", flags)) { | |
a = map(i, 0, count, 0, TWO_PI); | |
} | |
float x = r * cos(a); | |
float y = r * sin(a); | |
float d = dist(x, y, 0, 0); | |
float dN = map(d, startR, endR, 0, 1); | |
float size = lerp(minPSize, maxPSize, dN); | |
cloud.add(new Particle(x, y, 0, size, deviation, flags)); | |
} | |
return cloud; | |
} | |
class Particle { | |
String[] flags; | |
PVector pos; | |
PVector localRotPos; | |
PVector localRotSpd; | |
float orbitalRotAngle; | |
float orbitalRotPos; | |
float r; | |
float boxW, boxH, boxD; | |
boolean fill; | |
boolean isBox; | |
int sphereDetail; | |
int foregroundColor; | |
Particle(float x, float y, float z, float size, float deviation, String... flags) { | |
this.r = size; | |
pos = new PVector(x, y, z); | |
orbitalRotAngle = random(-deviation, deviation); | |
orbitalRotPos = random(-deviation, deviation); | |
if(contains("restrictedYDeviation", flags)){ | |
orbitalRotPos = 0; | |
} | |
localRotPos = new PVector(random(PI), random(PI), random(PI)); | |
localRotSpd = new PVector(rr(rotationMaxSpeed), rr(rotationMaxSpeed), rr(rotationMaxSpeed)); | |
if (contains("noLocalRot", flags)) { | |
localRotPos = new PVector(); | |
localRotSpd = new PVector(); | |
} | |
fill = true; | |
isBox = random(1) > .5f; | |
boxW = random(r); | |
boxH = random(r); | |
boxD = random(r); | |
sphereDetail = floor(random(1, maxSphereDetail)); | |
this.flags = flags; | |
flagCorrection(flags); | |
} | |
private void flagCorrection(String[] flags) { | |
if (contains("sphere", flags)) { | |
isBox = false; | |
} | |
if (contains("box", flags)) { | |
isBox = true; | |
boxW = r; | |
boxH = r; | |
boxD = r; | |
if(contains("obelisk", flags)){ | |
boxD *= 3; | |
} | |
} | |
} | |
void draw() { | |
if (r <= 0) { | |
return; | |
} | |
resetForeground(); | |
pushMatrix(); | |
rotateY(orbitalRotPos); | |
rotateX(orbitalRotAngle); | |
rotateZ(linearTime); | |
translate(pos.x, pos.y, pos.z); | |
rotateZ(linearTime); | |
if (fill) { | |
fill(0); | |
noStroke(); | |
ambient(foregroundColor); | |
specular(foregroundColor); | |
} else { | |
noFill(); | |
strokeWeight(1); | |
stroke(255); | |
} | |
if (onPC) { | |
shader(phong); | |
} | |
if (isBox) { | |
box(boxW, boxH, boxD); | |
} else { | |
pushMatrix(); | |
scale(r / baseShapeRadius); | |
shape(tesselatedSpheresIndexedByDetailLevel[sphereDetail]); | |
popMatrix(); | |
} | |
if (particles.indexOf(this) == particles.size() - 1) { | |
if (contains("noLocalRot", flags)) { | |
// coords(); | |
} | |
} | |
popMatrix(); | |
} | |
void resetForeground() { | |
if (particles.size() == 0) { | |
return; | |
} | |
colorMode(HSB, 360, 1, 1, 1); | |
int i = particles.indexOf(this); | |
float iN = map(i, 0, particles.size(), 0, 1); | |
if (contains("deterministicRotPos", flags)) { | |
iN = 0; | |
} | |
float hue = (-linearTime/TWO_PI*360)%360 + iN * 120f; | |
foregroundColor = color(rybToHsb(hue), 1f, 1f); | |
colorMode(RGB, 255, 255, 255, 100); | |
} | |
} | |
// - utility methods | |
private void backgroundGradient() { | |
noStroke(); | |
pushMatrix(); | |
beginShape(); | |
fill(backgroundColorA); | |
vertex(0, 0); | |
vertex(width, 0); | |
fill(backgroundColorB); | |
vertex(width, height); | |
vertex(0, height); | |
endShape(CLOSE); | |
popMatrix(); | |
} | |
public void mouseDragged() { | |
rotSpd += radians(pmouseX - mouseX) / 120f; | |
} | |
private float mx() { | |
float val = map(mouseX, 0, screen, 0, 1); | |
println("mx: " + val); | |
return val; | |
} | |
private float my() { | |
float val = map(mouseY, 0, height, 0, 1); | |
println("my: " + val); | |
return val; | |
} | |
private void coords() { | |
pushStyle(); | |
strokeWeight(5); | |
float mag = 300; | |
stroke(255, 0, 0); | |
line(-mag, 0, 0, mag, 0, 0); | |
stroke(0, 255, 0); | |
line(0, -mag, 0, 0, mag, 0); | |
stroke(0, 0, 255); | |
line(0, 0, -mag, 0, 0, mag); | |
popStyle(); | |
} | |
float rr(float a) { | |
return random(-a, a); | |
} | |
boolean contains(String key, String[] set) { | |
for (String s : set) { | |
if (s.equals(key)) return true; | |
} | |
return false; | |
} | |
// - amazing tessellated sphere by nking who helped me a lot on this, thanks! | |
// https://www.shadertoy.com/user/nking | |
PShape createSphere(float r, int detail) { | |
PShape res = createShape(); | |
float deg5 = TWO_PI / 5f; | |
float deg6 = acos((1f + sqrt(5f)) / (5f + sqrt(5f))); | |
PVector top = new PVector(0, r, 0); | |
PVector[] sides = new PVector[5]; | |
for (int i = 0; i < 5; i++) { | |
sides[i] = new PVector( | |
r * sin(deg6) * cos(deg5 * i), | |
r * cos(deg6), | |
r * sin(deg6) * sin(deg5 * i)); | |
} | |
res.disableStyle(); | |
res.beginShape(TRIANGLES); | |
for (int i = 0; i < 5; i++) { | |
trig(res, r, top, sides[(i + 1) % 5], sides[i], detail); | |
trig(res, r, sides[i], flip(sides[(i + 3) % 5]), flip(sides[(i + 2) % 5]), detail); | |
trig(res, r, flip(sides[i]), sides[(i + 2) % 5], sides[(i + 3) % 5], detail); | |
trig(res, r, flip(top), flip(sides[i]), flip(sides[(i + 1) % 5]), detail); | |
} | |
res.endShape(); | |
return res; | |
} | |
PVector flip(PVector v) { | |
return new PVector(-v.x, -v.y, -v.z); | |
} | |
void trig(PShape ps, float r, PVector p1, PVector p2, PVector p3, int detail) { | |
if (detail > 1) { | |
PVector mid12 = PVector.add(p1, p2); | |
mid12.setMag(r); | |
PVector mid23 = PVector.add(p2, p3); | |
mid23.setMag(r); | |
PVector mid13 = PVector.add(p1, p3); | |
mid13.setMag(r); | |
detail--; | |
trig(ps, r, p1, mid12, mid13, detail); | |
trig(ps, r, p2, mid23, mid12, detail); | |
trig(ps, r, p3, mid13, mid23, detail); | |
trig(ps, r, mid12, mid23, mid13, detail); | |
} else { | |
PVector dir = PVector.add(p1, p2); | |
dir.add(p3); | |
normal(ps, dir); | |
vertex(ps, p1); | |
vertex(ps, p2); | |
vertex(ps, p3); | |
} | |
} | |
void vertex(PShape ps, PVector v) { | |
ps.vertex(v.x, v.y, v.z); | |
} | |
void normal(PShape ps, PVector v) { | |
ps.normal(v.x, v.y, v.z); | |
} | |
// - brilliant color correction by sighack | |
//https://sighack.com/post/procedural-color-algorithms-hsb-vs-ryb | |
float rybToHsb(float hue) { | |
hue = (360 - hue) % 360; | |
hue = hue % 360; | |
float ryb_hue = 0; | |
float[][] ryb_wheel = { | |
{0, 0}, {15, 8}, {30, 17}, {45, 26}, | |
{60, 34}, {75, 41}, {90, 48}, {105, 54}, | |
{120, 60}, {135, 81}, {150, 103}, {165, 123}, | |
{180, 138}, {195, 155}, {210, 171}, {225, 187}, | |
{240, 204}, {255, 219}, {270, 234}, {285, 251}, | |
{300, 267}, {315, 282}, {330, 298}, {345, 329}, | |
{360, 0} | |
}; | |
for (int i = 0; i < ryb_wheel.length - 1; i++) { | |
float x0 = ryb_wheel[i][0]; | |
float y0 = ryb_wheel[i][1]; | |
float x1 = ryb_wheel[i + 1][0]; | |
float y1 = ryb_wheel[i + 1][1]; | |
/* Ensure that y1 > y0 */ | |
if (y1 < y0) | |
y1 += 360; | |
/* If hue lies between y0 and y1, do linear mapping */ | |
if (hue >= x0 && hue < x1) { | |
ryb_hue = map(hue, x0, x1, y0, y1) % 360; | |
break; | |
} | |
} | |
return ryb_hue; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Part of the Processing project - http://processing.org | |
Copyright (c) 2012-15 The Processing Foundation | |
Copyright (c) 2004-12 Ben Fry and Casey Reas | |
Copyright (c) 2001-04 Massachusetts Institute of Technology | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation, version 2.1. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General | |
Public License along with this library; if not, write to the | |
Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
Boston, MA 02111-1307 USA | |
*/ | |
#ifdef GL_ES | |
precision mediump float; | |
precision mediump int; | |
#endif | |
uniform int lightCount; | |
uniform vec4 lightPosition[8]; | |
uniform vec3 lightNormal[8]; | |
uniform vec3 lightAmbient[8]; | |
uniform vec3 lightDiffuse[8]; | |
uniform vec3 lightSpecular[8]; | |
uniform vec3 lightFalloff[8]; | |
uniform vec2 lightSpot[8]; | |
uniform float distance; | |
in vec4 vAmbient; | |
in vec4 vSpecular; | |
in vec4 vEmissive; | |
in float vShininess; | |
in vec4 vColor; | |
in vec3 ecVertex; | |
in vec3 vEcNormal; | |
const float zero_float = 0.0; | |
const float one_float = 1.0; | |
const vec3 zero_vec3 = vec3(0); | |
float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) { | |
vec3 lpv = lightPos - vertPos; | |
vec3 dist = vec3(one_float); | |
dist.z = dot(lpv, lpv); | |
dist.y = sqrt(dist.z); | |
return one_float / dot(dist, coeff); | |
} | |
float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) { | |
vec3 lpv = normalize(lightPos - vertPos); | |
vec3 nln = -one_float * lightNorm; | |
float spotCos = dot(nln, lpv); | |
return spotCos <= minCos ? zero_float : pow(spotCos, spotExp); | |
} | |
float lambertFactor(vec3 lightDir, vec3 vecNormal) { | |
return max(zero_float, dot(lightDir, vecNormal)); | |
} | |
float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) { | |
vec3 np = normalize(vertPos); | |
vec3 ldp = normalize(lightDir - np); | |
return pow(max(zero_float, dot(ldp, vecNormal)), shine); | |
} | |
void main() { | |
vec3 ecNormal = normalize(vEcNormal); | |
vec3 ecNormalInv = ecNormal * -one_float; | |
vec4 color = vColor; | |
vec4 ambient = vAmbient; | |
vec4 specular = vSpecular; | |
vec4 emissive = vEmissive; | |
float shininess = vShininess; | |
// Light calculations | |
vec3 totalAmbient = vec3(0, 0, 0); | |
vec3 totalFrontDiffuse = vec3(0, 0, 0); | |
vec3 totalFrontSpecular = vec3(0, 0, 0); | |
vec3 totalBackDiffuse = vec3(0, 0, 0); | |
vec3 totalBackSpecular = vec3(0, 0, 0); | |
for (int i = 0; i < 8; i++) { | |
if (lightCount == i) break; | |
vec3 lightPos = lightPosition[i].xyz; | |
bool isDir = lightPosition[i].w < one_float; | |
float spotCos = lightSpot[i].x; | |
float spotExp = lightSpot[i].y; | |
vec3 lightDir; | |
float falloff; | |
float spotf; | |
if (isDir) { | |
falloff = one_float; | |
lightDir = -one_float * lightNormal[i]; | |
} else { | |
falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]); | |
lightDir = normalize(lightPos - ecVertex); | |
} | |
spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i], | |
spotCos, spotExp) | |
: one_float; | |
if (any(greaterThan(lightAmbient[i], zero_vec3))) { | |
totalAmbient += lightAmbient[i] * falloff; | |
} | |
if (any(greaterThan(lightDiffuse[i], zero_vec3))) { | |
totalFrontDiffuse += lightDiffuse[i] * falloff * spotf * | |
lambertFactor(lightDir, ecNormal); | |
totalBackDiffuse += lightDiffuse[i] * falloff * spotf * | |
lambertFactor(lightDir, ecNormalInv); | |
} | |
if (any(greaterThan(lightSpecular[i], zero_vec3))) { | |
totalFrontSpecular += lightSpecular[i] * falloff * spotf * | |
blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess); | |
totalBackSpecular += lightSpecular[i] * falloff * spotf * | |
blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess); | |
} | |
} | |
// Calculating final color as result of all lights (plus emissive term). | |
// Transparency is determined exclusively by the diffuse component. | |
vec4 vertColor = vec4(totalAmbient, 0) * ambient + | |
vec4(totalFrontDiffuse, 1) * color + | |
vec4(totalFrontSpecular, 0) * specular + | |
vec4(emissive.rgb, 0); | |
vec4 backVertColor = vec4(totalAmbient, 0) * ambient + | |
vec4(totalBackDiffuse, 1) * color + | |
vec4(totalBackSpecular, 0) * specular + | |
vec4(emissive.rgb, 0); | |
gl_FragColor = gl_FrontFacing ? vertColor : backVertColor; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Part of the Processing project - http://processing.org | |
Copyright (c) 2012-15 The Processing Foundation | |
Copyright (c) 2004-12 Ben Fry and Casey Reas | |
Copyright (c) 2001-04 Massachusetts Institute of Technology | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation, version 2.1. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General | |
Public License along with this library; if not, write to the | |
Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
Boston, MA 02111-1307 USA | |
*/ | |
uniform mat4 modelviewMatrix; | |
uniform mat4 transformMatrix; | |
uniform mat3 normalMatrix; | |
uniform int lightCount; | |
uniform vec4 lightPosition[8]; | |
uniform vec3 lightNormal[8]; | |
uniform vec3 lightAmbient[8]; | |
uniform vec3 lightDiffuse[8]; | |
uniform vec3 lightSpecular[8]; | |
uniform vec3 lightFalloff[8]; | |
uniform vec2 lightSpot[8]; | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec3 normal; | |
out vec4 vColor; | |
attribute vec4 ambient; | |
attribute vec4 specular; | |
attribute vec4 emissive; | |
attribute float shininess; | |
out vec4 vAmbient; | |
out vec4 vSpecular; | |
out vec4 vEmissive; | |
out float vShininess; | |
out vec3 ecVertex; | |
out vec3 vEcNormal; | |
const float zero_float = 0.0; | |
const float one_float = 1.0; | |
const vec3 zero_vec3 = vec3(0); | |
void main() { | |
// Vertex in clip coordinates | |
gl_Position = transformMatrix * position; | |
// Vertex in eye coordinates | |
ecVertex = vec3(modelviewMatrix * position); | |
// Normal vector in eye coordinates | |
vEcNormal = normalize(normalMatrix * normal); | |
vColor = color; | |
vAmbient = ambient; | |
vSpecular = specular; | |
vShininess = shininess; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment