Add metaball scene
This commit is contained in:
parent
ee29365824
commit
39ed626509
8 changed files with 140 additions and 16 deletions
|
|
@ -45,7 +45,7 @@
|
||||||
"resolve-url-loader": "^3.1.1",
|
"resolve-url-loader": "^3.1.1",
|
||||||
"sass": "^1.26.3",
|
"sass": "^1.26.3",
|
||||||
"sass-loader": "^9.0.3",
|
"sass-loader": "^9.0.3",
|
||||||
"sdf-2d": "^0.3.4",
|
"sdf-2d": "^0.3.6",
|
||||||
"source-map-loader": "^1.1.0",
|
"source-map-loader": "^1.1.0",
|
||||||
"svg-url-loader": "^6.0.0",
|
"svg-url-loader": "^6.0.0",
|
||||||
"terser-webpack-plugin": "^2.3.8",
|
"terser-webpack-plugin": "^2.3.8",
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ import '../static/og-image.png';
|
||||||
import { DeltaTimeCalculator } from './helper/delta-time-calculator';
|
import { DeltaTimeCalculator } from './helper/delta-time-calculator';
|
||||||
import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines';
|
import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines';
|
||||||
import { BlobScene } from './scenes/blob/blob-scene';
|
import { BlobScene } from './scenes/blob/blob-scene';
|
||||||
|
import { MetaballScene } from './scenes/metaball/metaball-scene';
|
||||||
import { RainScene } from './scenes/rain/rain-scene';
|
import { RainScene } from './scenes/rain/rain-scene';
|
||||||
import { Scene } from './scenes/scene';
|
import { Scene } from './scenes/scene';
|
||||||
import { TunnelScene } from './scenes/tunnel-scene';
|
import { TunnelScene } from './scenes/tunnel-scene';
|
||||||
import './styles/index.scss';
|
import './styles/index.scss';
|
||||||
|
|
||||||
const scenes = [TunnelScene, RainScene, BlobScene];
|
const scenes = [TunnelScene, MetaballScene, RainScene, BlobScene];
|
||||||
const sceneIntervalInSeconds = 8;
|
const sceneIntervalInSeconds = 8;
|
||||||
|
|
||||||
glMatrix.setMatrixArrayType(Array);
|
glMatrix.setMatrixArrayType(Array);
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ export class Blob extends Drawable {
|
||||||
headCenter: 'headCenters',
|
headCenter: 'headCenters',
|
||||||
},
|
},
|
||||||
uniformCountMacroName: 'BLOB_COUNT',
|
uniformCountMacroName: 'BLOB_COUNT',
|
||||||
shaderCombinationSteps: [1],
|
shaderCombinationSteps: [0, 1],
|
||||||
empty: new Blob(vec2.fromValues(0, 0)),
|
empty: new Blob(vec2.fromValues(0, 0)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
104
src/scenes/metaball/metaball-scene.ts
Normal file
104
src/scenes/metaball/metaball-scene.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { compile, Flashlight, MetaCircle, Renderer } from 'sdf-2d';
|
||||||
|
import { prettyPrint } from '../../helper/pretty-print';
|
||||||
|
import { Random } from '../../helper/random';
|
||||||
|
import { rgb } from '../../helper/rgb';
|
||||||
|
import { rgb255 } from '../../helper/rgb255';
|
||||||
|
import { Scene } from '../scene';
|
||||||
|
import { Metaball } from './metaball';
|
||||||
|
|
||||||
|
export class MetaballScene implements Scene {
|
||||||
|
private circles: Array<Metaball> = [];
|
||||||
|
|
||||||
|
private renderer: Renderer;
|
||||||
|
private canvas: HTMLCanvasElement;
|
||||||
|
private overlay: HTMLDivElement;
|
||||||
|
|
||||||
|
public async initialize(
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
overlay: HTMLDivElement
|
||||||
|
): Promise<void> {
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.overlay = overlay;
|
||||||
|
this.renderer = await compile(canvas, [
|
||||||
|
{
|
||||||
|
...Flashlight.descriptor,
|
||||||
|
shaderCombinationSteps: [0, 2],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...MetaCircle.descriptor,
|
||||||
|
shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.renderer.setRuntimeSettings({
|
||||||
|
ambientLight: rgb(0.1, 0.1, 0.3),
|
||||||
|
colorPalette: [
|
||||||
|
rgb(1, 1, 1),
|
||||||
|
rgb(1, 1, 1),
|
||||||
|
rgb(1, 1, 1),
|
||||||
|
rgb(1, 1, 1),
|
||||||
|
rgb(1, 1, 0),
|
||||||
|
rgb255(186, 59, 70),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
this.circles.push(
|
||||||
|
new Metaball(
|
||||||
|
vec2.fromValues(
|
||||||
|
Random.getRandomInRange(0.3, 0.6),
|
||||||
|
Random.getRandomInRange(0.3, 0.6)
|
||||||
|
),
|
||||||
|
vec2.fromValues(
|
||||||
|
Random.getRandomInRange(0.05, 0.5),
|
||||||
|
Random.getRandomInRange(0.05, 0.5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public drawNextFrame(
|
||||||
|
currentTime: DOMHighResTimeStamp,
|
||||||
|
deltaTime: DOMHighResTimeStamp
|
||||||
|
): void {
|
||||||
|
const { width, height } = this.canvas.getBoundingClientRect();
|
||||||
|
const viewAreaWidth = width / Math.max(width, height);
|
||||||
|
const viewAreaHeight = height / Math.max(width, height);
|
||||||
|
this.renderer.setViewArea(
|
||||||
|
vec2.fromValues(0, viewAreaHeight),
|
||||||
|
vec2.fromValues(viewAreaWidth, viewAreaHeight)
|
||||||
|
);
|
||||||
|
this.renderer.autoscaleQuality(deltaTime);
|
||||||
|
|
||||||
|
this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||||
|
|
||||||
|
this.circles.forEach((c) => {
|
||||||
|
c.animate(currentTime / 2000, viewAreaWidth, viewAreaHeight);
|
||||||
|
this.renderer.addDrawable(c.shape);
|
||||||
|
});
|
||||||
|
|
||||||
|
const light1 = new Flashlight(
|
||||||
|
vec2.fromValues(-0.05, -0.05),
|
||||||
|
rgb255(104, 171, 212),
|
||||||
|
0.02,
|
||||||
|
vec2.fromValues(1, 1)
|
||||||
|
);
|
||||||
|
const light2 = new Flashlight(
|
||||||
|
vec2.fromValues(viewAreaWidth + 0.05, -0.05),
|
||||||
|
rgb255(226, 90, 102),
|
||||||
|
0.02,
|
||||||
|
vec2.fromValues(-1, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.renderer.addDrawable(light1);
|
||||||
|
this.renderer.addDrawable(light2);
|
||||||
|
|
||||||
|
this.renderer.renderDrawables();
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this.renderer.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/scenes/metaball/metaball.ts
Normal file
21
src/scenes/metaball/metaball.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { MetaCircle } from 'sdf-2d';
|
||||||
|
import { Random } from '../../helper/random';
|
||||||
|
|
||||||
|
export class Metaball {
|
||||||
|
public shape = new MetaCircle(vec2.create(), Random.getRandomInRange(0.025, 0.075));
|
||||||
|
|
||||||
|
private direction = Random.getRandom() > 0.5 ? 1 : -1;
|
||||||
|
private speed = Random.getRandomInRange(0.5, 2);
|
||||||
|
constructor(private readonly center: vec2, private readonly size: vec2) {}
|
||||||
|
|
||||||
|
public animate(currentTime: DOMHighResTimeStamp, width: number, height: number) {
|
||||||
|
vec2.set(
|
||||||
|
this.shape.center,
|
||||||
|
this.size.x * Math.cos(currentTime * this.speed * this.direction) +
|
||||||
|
this.center.x * width,
|
||||||
|
this.size.y * Math.sin(currentTime * this.speed * this.direction) +
|
||||||
|
this.center.y * height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { Tunnel } from 'sdf-2d';
|
import { Droplet } from 'sdf-2d';
|
||||||
import { Random } from '../../helper/random';
|
import { Random } from '../../helper/random';
|
||||||
|
|
||||||
export class Droplet {
|
export class DropletWrapper {
|
||||||
public readonly drawable: Tunnel;
|
public readonly drawable: Droplet;
|
||||||
|
|
||||||
private speed = Random.getRandom() * 0.2 + 0.2;
|
private speed = Random.getRandom() * 0.2 + 0.2;
|
||||||
private position = vec2.fromValues(
|
private position = vec2.fromValues(
|
||||||
|
|
@ -15,7 +15,7 @@ export class Droplet {
|
||||||
constructor() {
|
constructor() {
|
||||||
const size = Random.getRandom() * 2 + 2;
|
const size = Random.getRandom() * 2 + 2;
|
||||||
|
|
||||||
this.drawable = new Tunnel(
|
this.drawable = new Droplet(
|
||||||
vec2.create(),
|
vec2.create(),
|
||||||
vec2.create(),
|
vec2.create(),
|
||||||
size + Random.getRandom() * 2 + 2,
|
size + Random.getRandom() * 2 + 2,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { CircleLight, compile, Renderer, Tunnel } from 'sdf-2d';
|
import { CircleLight, compile, Droplet, Renderer } from 'sdf-2d';
|
||||||
import { prettyPrint } from '../../helper/pretty-print';
|
import { prettyPrint } from '../../helper/pretty-print';
|
||||||
import { rgb } from '../../helper/rgb';
|
import { rgb } from '../../helper/rgb';
|
||||||
import { rgb255 } from '../../helper/rgb255';
|
import { rgb255 } from '../../helper/rgb255';
|
||||||
import { Scene } from '../scene';
|
import { Scene } from '../scene';
|
||||||
import { Droplet } from './droplet';
|
import { DropletWrapper } from './droplet';
|
||||||
|
|
||||||
export class RainScene implements Scene {
|
export class RainScene implements Scene {
|
||||||
private droplets: Array<Droplet> = [];
|
private droplets: Array<DropletWrapper> = [];
|
||||||
private light1: CircleLight = new CircleLight(vec2.create(), rgb255(184, 41, 255), 2);
|
private light1: CircleLight = new CircleLight(vec2.create(), rgb255(184, 41, 255), 2);
|
||||||
private light2: CircleLight = new CircleLight(vec2.create(), rgb255(255, 31, 109), 2);
|
private light2: CircleLight = new CircleLight(vec2.create(), rgb255(255, 31, 109), 2);
|
||||||
|
|
||||||
|
|
@ -23,12 +23,12 @@ export class RainScene implements Scene {
|
||||||
this.overlay = overlay;
|
this.overlay = overlay;
|
||||||
this.renderer = await compile(canvas, [
|
this.renderer = await compile(canvas, [
|
||||||
{
|
{
|
||||||
...Tunnel.descriptor,
|
...Droplet.descriptor,
|
||||||
shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16, 24],
|
shaderCombinationSteps: [0, 1, 2, 4, 8, 12, 16, 24],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...CircleLight.descriptor,
|
...CircleLight.descriptor,
|
||||||
shaderCombinationSteps: [2],
|
shaderCombinationSteps: [0, 2],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -36,11 +36,10 @@ export class RainScene implements Scene {
|
||||||
ambientLight: rgb(0.2, 0.2, 0.2),
|
ambientLight: rgb(0.2, 0.2, 0.2),
|
||||||
backgroundColor: rgb(1, 1, 1),
|
backgroundColor: rgb(1, 1, 1),
|
||||||
colorPalette: [rgb(1, 1, 1), rgb(0.3, 1, 1), rgb(1, 1, 0), rgb(0.3, 1, 1)],
|
colorPalette: [rgb(1, 1, 1), rgb(0.3, 1, 1), rgb(1, 1, 0), rgb(0.3, 1, 1)],
|
||||||
enableHighDpiRendering: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < (canvas.getBoundingClientRect().width / 800) * 20; i++) {
|
for (let i = 0; i < (canvas.getBoundingClientRect().width / 800) * 20; i++) {
|
||||||
this.droplets.push(new Droplet());
|
this.droplets.push(new DropletWrapper());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ export class TunnelScene implements Scene {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...CircleLight.descriptor,
|
...CircleLight.descriptor,
|
||||||
shaderCombinationSteps: [1, 2, 3, 4, 5, 6, 7],
|
shaderCombinationSteps: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -81,7 +81,6 @@ export class TunnelScene implements Scene {
|
||||||
ambientLight: rgb(0.35, 0.1, 0.45),
|
ambientLight: rgb(0.35, 0.1, 0.45),
|
||||||
backgroundColor: rgba(1, 1, 1, 1),
|
backgroundColor: rgba(1, 1, 1, 1),
|
||||||
colorPalette: [rgb(0.4, 0.5, 0.6), rgb(0, 0, 0), rgb(0, 0, 0), rgb(0, 0, 0)],
|
colorPalette: [rgb(0.4, 0.5, 0.6), rgb(0, 0, 0), rgb(0, 0, 0), rgb(0, 0, 0)],
|
||||||
enableHighDpiRendering: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < 200; i++) {
|
for (let i = 0; i < 200; i++) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue