Update project

This commit is contained in:
schmelczerandras 2020-09-20 20:15:27 +02:00
commit fd64d9491d
2 changed files with 309 additions and 97 deletions

View file

@ -0,0 +1,94 @@
import { vec2, vec3 } from 'gl-matrix';
import { Circle, CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d';
import { prettyPrint } from '../../helper/pretty-print';
import { Scene } from '../scene';
import { Blob } from './blob';
export class BlobScene implements Scene {
private renderer: Renderer;
private canvas: HTMLCanvasElement;
private overlay: HTMLDivElement;
private tunnels: Array<InvertedTunnel> = [];
private lights: Array<CircleLight> = [];
public async initialize(
canvas: HTMLCanvasElement,
overlay: HTMLDivElement
): Promise<void> {
this.canvas = canvas;
this.overlay = overlay;
this.renderer = await compile(
canvas,
[
Circle.descriptor,
{
...CircleLight.descriptor,
shaderCombinationSteps: [1, 2],
},
Blob.descriptor,
],
[
vec3.fromValues(0, 0, 0),
vec3.fromValues(224 / 255, 96 / 255, 126 / 255),
vec3.fromValues(119 / 255, 173 / 255, 120 / 255),
]
);
this.renderer.setRuntimeSettings({
ambientLight: vec3.fromValues(0.35, 0.1, 0.45),
shadowLength: 800,
});
const { width, height } = this.canvas.getBoundingClientRect();
const length = vec2.length([width, height]);
this.blob = new Blob([width / 2, -length / 4 + length / 2]);
}
private blob: Blob;
private deltaSinceStart = 0;
public drawNextFrame(
currentTime: DOMHighResTimeStamp,
deltaTime: DOMHighResTimeStamp
): void {
const { width, height } = this.canvas.getBoundingClientRect();
this.deltaSinceStart += deltaTime;
this.renderer.setViewArea([0, height], [width, height]);
this.renderer.autoscaleQuality(deltaTime);
this.overlay.innerText = prettyPrint(this.renderer.insights);
const length = vec2.length([width, height]);
const q = (this.deltaSinceStart % 8000) / 4000;
this.blob.animate(this.deltaSinceStart);
[
new Circle([width / 2, -length / 4], length / 2),
this.blob,
new CircleLight(
[
(Math.cos((1 - q) * Math.PI) * length) / 2 + width / 2,
(Math.sin((1 - q) * Math.PI) * length) / 2,
],
[1, 0.8, 0],
1
),
new CircleLight(
[
(Math.cos(-q * Math.PI) * length) / 2 + width / 2,
(Math.sin(-q * Math.PI) * length) / 2,
],
[0, 0.8, 1],
1
),
].forEach((d) => this.renderer.addDrawable(d));
this.renderer.renderDrawables();
}
public destroy(): void {
this.renderer.destroy();
}
}

139
src/scenes/blob/blob.ts Normal file
View file

@ -0,0 +1,139 @@
import { mat2d, vec2 } from 'gl-matrix';
import { Circle, Drawable, DrawableDescriptor } from 'sdf-2d';
export class Blob extends Drawable {
public static descriptor: DrawableDescriptor = {
sdf: {
shader: `
uniform struct {
vec2 headCenter;
vec2 leftFootCenter;
vec2 rightFootCenter;
float headRadius;
float footRadius;
float k;
}[BLOB_COUNT] blobs;
float smoothMin(float a, float b)
{
const float k = 80.0;
float res = exp2( -k*a ) + exp2( -k*b );
return -log2( res )/k;
}
float circleDistance(vec2 circleCenter, float radius) {
return distance(position, circleCenter) - radius;
}
void blobMinDistance(inout float minDistance, inout float color) {
for (int i = 0; i < BLOB_COUNT; i++) {
float headDistance = circleDistance(blobs[i].headCenter, blobs[i].headRadius);
float leftFootDistance = circleDistance(blobs[i].leftFootCenter, blobs[i].footRadius);
float rightFootDistance = circleDistance(blobs[i].rightFootCenter, blobs[i].footRadius);
float res = min(
smoothMin(headDistance, leftFootDistance),
smoothMin(headDistance, rightFootDistance)
);
minDistance = min(minDistance, res);
color = mix(1.0, color, step(distanceNdcPixelSize + SURFACE_OFFSET, res));
}
}
`,
distanceFunctionName: 'blobMinDistance',
},
uniformName: 'blobs',
uniformCountMacroName: 'BLOB_COUNT',
shaderCombinationSteps: [1],
empty: new Blob(vec2.fromValues(0, 0)),
};
public readonly boundingCircleRadius = 200;
protected readonly headRadius = 70;
protected readonly footRadius = 30;
private readonly headOffset = vec2.fromValues(0, 120);
private leftFootOffset = vec2.fromValues(-30, this.footRadius);
private rightFootOffset = vec2.fromValues(30, this.footRadius);
private leftFootOffsetDefault = vec2.fromValues(-30, this.footRadius);
private rightFootOffsetDefault = vec2.fromValues(30, this.footRadius);
protected boundingCircle = new Circle(vec2.create(), this.boundingCircleRadius);
protected head = new Circle(vec2.create(), this.headRadius);
protected leftFoot = new Circle(vec2.create(), this.footRadius);
protected rightFoot = new Circle(vec2.create(), this.footRadius);
public constructor(private center: vec2) {
super();
this.position = center;
}
public set position(value: vec2) {
vec2.copy(this.boundingCircle.center, value);
vec2.add(this.head.center, value, this.headOffset);
vec2.add(this.leftFoot.center, value, this.leftFootOffset);
vec2.add(this.rightFoot.center, value, this.rightFootOffset);
}
public animate(time: number) {
const offset = 20;
const q = (time % 1000) / 500;
vec2.subtract(
this.rightFootOffset,
this.rightFootOffsetDefault,
vec2.fromValues(q * offset, 0)
);
vec2.subtract(
this.leftFootOffset,
this.leftFootOffsetDefault,
vec2.fromValues(q * offset, 0)
);
vec2.add(
this.rightFootOffset,
this.rightFootOffset,
vec2.fromValues(
Math.min(1, q) * offset * 2,
Math.sin(Math.min(1, q) * Math.PI) * 10
)
);
vec2.add(
this.leftFootOffset,
this.leftFootOffset,
vec2.fromValues(
(q > 1 ? q - 1 : 0) * offset * 2,
Math.sin((q > 1 ? q - 1 : 0) * Math.PI) * 10
)
);
this.position = this.center;
}
public minDistance(target: vec2): number {
return this.boundingCircle.minDistance(target);
}
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
return {
headCenter: vec2.transformMat2d(vec2.create(), this.head.center, transform2d),
leftFootCenter: vec2.transformMat2d(
vec2.create(),
this.leftFoot.center,
transform2d
),
rightFootCenter: vec2.transformMat2d(
vec2.create(),
this.rightFoot.center,
transform2d
),
headRadius: this.headRadius * transform1d,
footRadius: this.footRadius * transform1d,
};
}
}