attribute vec3 aPosition;
attribute vec3 aPosition2;
attribute vec3 aPosition3;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;
uniform vec3 uLightingDirection[5];
uniform float uMorphRate;
varying vec3 vLightDirection;
//float morph = smoothstep(0.0, 0.1, fract(uMorphRate)) - smoothstep(0.5, 0.6, fract(uMorphRate));
float morph = uMorphRate;
vec3 position = mix(mix(aPosition, aPosition3, min(morph, 0.5) * 2.0), aPosition2, (max(0.5, morph) - 0.5) * 2.0);
vec4 viewModelPosition = uModelViewMatrix * vec4(position, 1.0);
gl_Position = uProjectionMatrix * viewModelPosition;
vec3 normal = mix(mix(aNormal, aPosition3, min(morph, 0.5) * 2.0), aNormal2, (max(0.5, morph) - 0.5) * 2.0);
vNormal = normalize(uNormalMatrix * normal);
vLightDirection = -uLightingDirection[0];
uniform vec4 uMaterialColor;
varying vec3 vLightDirection;
gl_FragColor = uMaterialColor;
vec3 normal = normalize(vNormal);
vec3 direction = normalize(vLightDirection);
float intensity = max(0.0, dot(direction, normal));
vec3 color1, color2, color3, color4, diffuseColor;
color1 = vec3(0.98, 1.0, 0.5);
color2 = vec3(0.5, 0.9, 0.2);
color3 = vec3(0.3, 0.4, 0.1);
color4 = vec3(0.2, 0.18, 0.0);
} else if (uColorMode == 1) {
color1 = vec3(1.0, 0.9, 0.98);
color2 = vec3(0.9, 0.5, 0.8);
color3 = vec3(0.5, 0.25, 0.3);
color4 = vec3(0.2, 0.18, 0.0);
} else if (uColorMode == 2) {
color1 = vec3(0.6, 0.98, 1.0);
color2 = vec3(0.4, 0.6, 0.95);
color3 = vec3(0.25, 0.3, 0.5);
color4 = vec3(0.2, 0.18, 0.0);
} else if (uColorMode == 3) {
color1 = vec3(0.98, 0.8, 1.0);
color2 = vec3(0.7, 0.35, 0.9);
color3 = vec3(0.35, 0.25, 0.5);
color4 = vec3(0.2, 0.18, 0.0);
} else if (uColorMode == 4) {
color1 = vec3(1.0, 0.98, 0.8);
color2 = vec3(0.95, 0.6, 0.3);
color3 = vec3(0.5, 0.3, 0.1);
color4 = vec3(0.2, 0.18, 0.0);
} else if (intensity > 0.75) {
} else if (intensity > 0.5) {
gl_FragColor.rgb = gl_FragColor.rgb * diffuseColor;
createCanvas(windowWidth, windowHeight, WEBGL);
this._renderer.retainedMode.buffers.fill.push(new p5.RenderBuffer(3, 'vertices2', 'vertexBuffer2', 'aPosition2', this._renderer, this._renderer._vToNArray));
this._renderer.retainedMode.buffers.fill.push(new p5.RenderBuffer(3, 'vertices3', 'vertexBuffer3', 'aPosition3', this._renderer, this._renderer._vToNArray));
this._renderer.retainedMode.buffers.fill.push(new p5.RenderBuffer(3, 'vertexNormals2', 'normalBuffer2', 'aNormal2', this._renderer, this._renderer._vToNArray));
myShader = createShader(vert, frag);
for (let i = -1; i < height / (s * 3 / 2) + 2; i++) {
for (let j = -1; j < width / (s * sqrt(3.0)) + 2; j++) {
colorMode[i+1].push(int(random(5)));
background(250, 240, 40);
directionalLight(255, 255, 255, 0.5, 0.3, -1);
if (frameCount % 240 == 0) {
morphMode = int(random(6));
t = (frameCount % 240) / 60;
for (let i = -1; i < height / (s * 3 / 2) + 2; i++) {
const y0 = i * s * 3 / 2 - height / 2;
for (let j = -1; j < width / (s * sqrt(3.0)) + 2; j++) {
const m = int(random(2));
const x0 = (j - (i % 2) * 0.5) * s * sqrt(3.0) - width / 2;
rate = x0 / width - 0.5 + t;
rate = - x0 / width - 0.5 + t;
rate = y0 / height - 0.5 + t;
rate = - y0 / height - 0.5 + t;
rate = dist(0, 0, x0, y0) / dist(0, 0, width / 2, height / 2) - 1.0 + t;
rate = - dist(0, 0, x0, y0) / dist(0, 0, width / 2, height / 2) + t;
myShader.setUniform("uMorphRate", lerp(morphFrom / 2.0, morphTo / 2.0, constrain(rate, 0, 1)));
myShader.setUniform("uColorMode", colorMode[i+1][j+1]);
rotateY(smoothFunction(constrain(rate * 0.5, 0, 1)) * PI);
morphObject(s * 0.5, 96, 48);
function morphObject(size, rows, columns) {
const gId = `morphObject|${rows}|${columns}`;
if (!this._renderer.geometryInHash(gId)) {
const morphGeom = new p5.Geometry();
sphereVertices.push(new p5.Vector(0, 0, 1));
for (let j = 0; j < columns - 1; j++) {
for (let i = 0; i < rows; i++) {
const r = sin(PI * (j + 1) / columns);
const theta = -TWO_PI * (i + 0.5) / rows;
let z = cos(PI * (j + 1) / columns);
sphereVertices.push(new p5.Vector(x, y, z));
sphereVertices.push(new p5.Vector(0, 0, -1));
heartVertices.push(new p5.Vector(0, 0, 0.5));
for (let j = 0; j < columns - 1; j++) {
for (let i = 0; i < rows; i++) {
const r = sin(PI * (j + 1) / columns);
const theta = - TWO_PI * (i + 0.5) / rows;
const x = 3.0 * r * (sin(theta) + r * 0.1 * sin(2 * theta) - r * 0.2 * sin(3 * theta)) / 2.5;
const y = 3.0 * r * (cos(theta) + 0.4 * r * cos(2 * theta) - r * 0.2 * cos(3 * theta)) / 2.5;
const z = 0.5 * cos(PI * (j + 1) / columns);
heartVertices.push(new p5.Vector(x, y, z));
heartVertices.push(new p5.Vector(0, 0, -0.5));
starVertices.push(new p5.Vector(0, 0, 0.5));
for (let j = 0; j < columns - 1; j++) {
for (let i = 0; i < rows; i++) {
const theta = - TWO_PI * (i + 0.5) / rows;
const n = 1.5 + 10 * (1 - sin(PI * (j + 1) / columns));
const rr = sin(PI * (j + 1) / columns);
const r = rr * pow(abs(pow(cos(5 * theta / 4), 4)) + abs(pow(sin(5 * theta / 4), 4)), - 1 / n);
const x = r * sin(theta);
const y = r * cos(theta);
const z = 0.5 * cos(PI * (j + 1) / columns);
starVertices.push(new p5.Vector(x, y, z));
starVertices.push(new p5.Vector(0, 0, -0.5));
for (let j=0; j<columns; j++) {
for (let i=0; i<rows; i++) {
morphGeom.faces.push([0, i+1, (i+1)%rows+1]);
} else if (j == columns-1) {
morphGeom.faces.push([i+1 + (j-1)*rows, 1 + j*rows, (i+1)%rows+1 + (j-1)*rows]);
morphGeom.faces.push([i+1 + (j-1)*rows, (i+1)%rows+1 + j*rows, (i+1)%rows+1 + (j-1)*rows]);
morphGeom.faces.push([i+1 + j*rows , (i+1)%rows+1 + j*rows, i+1 + (j-1)*rows ]);
morphGeom.vertices = starVertices;
morphGeom.computeNormals();
morphGeom.vertices2 = starVertices;
morphGeom.vertexNormals2 = morphGeom.vertexNormals.slice();
morphGeom.vertices = heartVertices;
morphGeom.computeNormals();
morphGeom.vertices3 = sphereVertices;
this._renderer.createBuffers(gId, morphGeom);
this._renderer.drawBuffersScaled(gId, size, size, size);
function smoothFunction(x) {
return 1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2);