Add basic tiled rendering
This commit is contained in:
parent
854e5a55a1
commit
edffd22c2e
26 changed files with 350 additions and 167 deletions
|
|
@ -1,13 +1,16 @@
|
|||
import { mat2d, vec2 } from 'gl-matrix';
|
||||
import { clamp } from '../helper/clamp';
|
||||
import { Circle } from '../math/circle';
|
||||
import { Rectangle } from '../math/rectangle';
|
||||
import { InfoText } from '../objects/types/info-text';
|
||||
import { DefaultFrameBuffer } from './graphics-library/frame-buffer/default-frame-buffer';
|
||||
import { IntermediateFrameBuffer } from './graphics-library/frame-buffer/intermediate-frame-buffer';
|
||||
import { WebGlStopwatch } from './graphics-library/helper/stopwatch';
|
||||
import { IProgram } from './graphics-library/program/i-program';
|
||||
import { UniformArrayAutoScalingProgram } from './graphics-library/program/uniform-array-autoscaling-program';
|
||||
import { IRenderer } from './i-renderer';
|
||||
import { Circle } from './primitives/circle';
|
||||
import { IPrimitive } from './primitives/i-primitive';
|
||||
import { Rectangle } from './primitives/rectangle';
|
||||
import { TunnelShape } from './primitives/tunnel-shape';
|
||||
|
||||
export class WebGl2Renderer implements IRenderer {
|
||||
private gl: WebGL2RenderingContext;
|
||||
|
|
@ -19,6 +22,12 @@ export class WebGl2Renderer implements IRenderer {
|
|||
private cursorPosition = vec2.create();
|
||||
private distanceFieldFrameBuffer: IntermediateFrameBuffer;
|
||||
private lightingFrameBuffer: DefaultFrameBuffer;
|
||||
private distanceProgram: IProgram;
|
||||
private lightingProgram: IProgram;
|
||||
|
||||
private primitives: Array<IPrimitive>;
|
||||
|
||||
private tileMultiplier = 5;
|
||||
|
||||
private targetDeltaTime = (1 / 30) * 1000;
|
||||
private deltaTimeError = (1 / 1000) * 1000;
|
||||
|
|
@ -46,7 +55,7 @@ export class WebGl2Renderer implements IRenderer {
|
|||
this.targetDeltaTime - this.deltaTimeError
|
||||
) {
|
||||
this.distanceFieldFrameBuffer.renderScale +=
|
||||
this.additiveQualityIncrease / 4;
|
||||
this.additiveQualityIncrease / 3;
|
||||
this.lightingFrameBuffer.renderScale += this.additiveQualityIncrease;
|
||||
} else if (
|
||||
this.exponentialDecayedDeltaTime >
|
||||
|
|
@ -91,39 +100,7 @@ export class WebGl2Renderer implements IRenderer {
|
|||
throw new Error('WebGl2 is not supported');
|
||||
}
|
||||
|
||||
const distanceScale = 64;
|
||||
|
||||
this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl, [
|
||||
new UniformArrayAutoScalingProgram(
|
||||
this.gl,
|
||||
shaderSources[0][0],
|
||||
shaderSources[0][1],
|
||||
{ distanceScale },
|
||||
{
|
||||
getValueFromUniforms: (v) => (v.lines ? v.lines.length / 2 : 0),
|
||||
uniformArraySizeName: 'lineCount',
|
||||
startingValue: 5,
|
||||
steps: 5,
|
||||
maximumValue: 100,
|
||||
}
|
||||
),
|
||||
]);
|
||||
|
||||
this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl, [
|
||||
new UniformArrayAutoScalingProgram(
|
||||
this.gl,
|
||||
shaderSources[1][0],
|
||||
shaderSources[1][1],
|
||||
{ distanceScale },
|
||||
{
|
||||
getValueFromUniforms: (v) => (v.lights ? v.lights.length : 0),
|
||||
uniformArraySizeName: 'lightCount',
|
||||
startingValue: 1,
|
||||
steps: 1,
|
||||
maximumValue: 8,
|
||||
}
|
||||
),
|
||||
]);
|
||||
this.createPipeline(shaderSources);
|
||||
|
||||
this.distanceFieldFrameBuffer.renderScale = 0.5;
|
||||
this.lightingFrameBuffer.renderScale = 1;
|
||||
|
|
@ -133,8 +110,49 @@ export class WebGl2Renderer implements IRenderer {
|
|||
} catch {}
|
||||
}
|
||||
|
||||
private createPipeline(shaderSources: Array<[string, string]>) {
|
||||
const distanceScale = 64;
|
||||
|
||||
this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl);
|
||||
this.distanceProgram = new UniformArrayAutoScalingProgram(
|
||||
this.gl,
|
||||
shaderSources[0][0],
|
||||
shaderSources[0][1],
|
||||
{ distanceScale },
|
||||
{
|
||||
getValueFromUniforms: (v) => (v.lines ? v.lines.length / 2 : 0),
|
||||
uniformArraySizeName: 'lineCount',
|
||||
startingValue: 0,
|
||||
enablingMacro: 'linesEnabled',
|
||||
steps: 1,
|
||||
maximumValue: 15,
|
||||
}
|
||||
);
|
||||
|
||||
this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl);
|
||||
this.lightingProgram = new UniformArrayAutoScalingProgram(
|
||||
this.gl,
|
||||
shaderSources[1][0],
|
||||
shaderSources[1][1],
|
||||
{ distanceScale },
|
||||
{
|
||||
getValueFromUniforms: (v) => (v.lights ? v.lights.length : 0),
|
||||
uniformArraySizeName: 'lightCount',
|
||||
startingValue: 1,
|
||||
enablingMacro: null,
|
||||
steps: 1,
|
||||
maximumValue: 8,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public drawPrimitive(primitive: IPrimitive) {
|
||||
this.primitives.push(primitive);
|
||||
}
|
||||
|
||||
public startFrame(deltaTime: DOMHighResTimeStamp): void {
|
||||
this.configureRenderScale(deltaTime);
|
||||
this.primitives = [];
|
||||
|
||||
this.stopwatch?.start();
|
||||
this.uniforms = {};
|
||||
|
|
@ -144,11 +162,81 @@ export class WebGl2Renderer implements IRenderer {
|
|||
|
||||
public finishFrame() {
|
||||
this.calculateOwnUniforms();
|
||||
this.distanceFieldFrameBuffer.render(this.uniforms);
|
||||
this.lightingFrameBuffer.render(
|
||||
this.uniforms,
|
||||
|
||||
this.distanceFieldFrameBuffer.bindAndClear();
|
||||
const q = 1 / this.tileMultiplier;
|
||||
const uvSize = vec2.fromValues(q, q);
|
||||
|
||||
const possiblyOnScreenPrimitives = this.primitives.filter(
|
||||
(p) => p.minimumDistance(this.viewCircle.center) < this.viewCircle.radius
|
||||
) as Array<TunnelShape>;
|
||||
|
||||
InfoText.modifyRecord(
|
||||
'nearby lines',
|
||||
possiblyOnScreenPrimitives.length.toString()
|
||||
);
|
||||
|
||||
const origin = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.fromValues(0, 0),
|
||||
this.uniforms.uvToWorld
|
||||
);
|
||||
|
||||
const firstCenter = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.fromValues(q, q),
|
||||
this.uniforms.uvToWorld
|
||||
);
|
||||
|
||||
vec2.subtract(firstCenter, firstCenter, origin);
|
||||
|
||||
const worldR = vec2.length(firstCenter);
|
||||
this.uniforms.maxMinDistance = 2 * worldR;
|
||||
|
||||
let sumLineCount = 0;
|
||||
|
||||
for (let x = 0; x < 1; x += q) {
|
||||
for (let y = 0; y < 1; y += q) {
|
||||
const uvBottomLeft = vec2.fromValues(x, y);
|
||||
this.distanceProgram.setDrawingRectangle(uvBottomLeft, uvSize);
|
||||
|
||||
const tileCenterWorldCoordinates = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.add(vec2.create(), uvBottomLeft, vec2.fromValues(q, q)),
|
||||
this.uniforms.uvToWorld
|
||||
);
|
||||
|
||||
const primitivesNearTile = possiblyOnScreenPrimitives.filter(
|
||||
(p) => p.distance(tileCenterWorldCoordinates) < 2 * worldR
|
||||
);
|
||||
|
||||
sumLineCount += primitivesNearTile.length;
|
||||
|
||||
this.uniforms.lines = [];
|
||||
this.uniforms.radii = [];
|
||||
|
||||
for (let tunnel of primitivesNearTile) {
|
||||
this.uniforms.lines.push(tunnel.from);
|
||||
this.uniforms.lines.push(tunnel.toFromDelta);
|
||||
this.uniforms.radii.push(tunnel.fromRadius);
|
||||
this.uniforms.radii.push(tunnel.toRadius);
|
||||
}
|
||||
|
||||
this.distanceProgram.bindAndSetUniforms(this.uniforms);
|
||||
this.distanceProgram.draw();
|
||||
}
|
||||
}
|
||||
|
||||
InfoText.modifyRecord(
|
||||
'lines',
|
||||
(sumLineCount / this.tileMultiplier / this.tileMultiplier).toFixed(2)
|
||||
);
|
||||
|
||||
this.lightingFrameBuffer.bindAndClear(
|
||||
this.distanceFieldFrameBuffer.colorTexture
|
||||
);
|
||||
this.lightingProgram.bindAndSetUniforms(this.uniforms);
|
||||
this.lightingProgram.draw();
|
||||
|
||||
this.stopwatch?.stop();
|
||||
}
|
||||
|
|
@ -158,13 +246,11 @@ export class WebGl2Renderer implements IRenderer {
|
|||
this.distanceFieldFrameBuffer.getSize()
|
||||
);
|
||||
|
||||
const ndcToWorld = mat2d.fromTranslation(
|
||||
const uvToWorld = mat2d.fromTranslation(
|
||||
mat2d.create(),
|
||||
this.viewBox.topLeft
|
||||
);
|
||||
mat2d.scale(ndcToWorld, ndcToWorld, this.viewBox.size);
|
||||
mat2d.scale(ndcToWorld, ndcToWorld, vec2.fromValues(0.5, 0.5));
|
||||
mat2d.translate(ndcToWorld, ndcToWorld, vec2.fromValues(1, 1));
|
||||
mat2d.scale(uvToWorld, uvToWorld, this.viewBox.size);
|
||||
|
||||
const worldToDistanceUV = mat2d.scale(
|
||||
mat2d.create(),
|
||||
|
|
@ -173,13 +259,20 @@ export class WebGl2Renderer implements IRenderer {
|
|||
);
|
||||
mat2d.invert(worldToDistanceUV, worldToDistanceUV);
|
||||
|
||||
const ndcToUv = mat2d.fromScaling(
|
||||
mat2d.create(),
|
||||
vec2.fromValues(0.5, 0.5)
|
||||
);
|
||||
mat2d.translate(ndcToUv, ndcToUv, vec2.fromValues(1, 1));
|
||||
|
||||
const cursorPosition = this.screenUvToWorldCoordinate(this.cursorPosition);
|
||||
|
||||
this.giveUniforms({
|
||||
distanceScreenToWorld,
|
||||
worldToDistanceUV,
|
||||
cursorPosition,
|
||||
ndcToWorld,
|
||||
ndcToUv,
|
||||
uvToWorld,
|
||||
viewBoxSize: this.viewBox.size,
|
||||
});
|
||||
}
|
||||
|
|
@ -241,6 +334,7 @@ export class WebGl2Renderer implements IRenderer {
|
|||
);
|
||||
|
||||
const halfDiagonal = vec2.scale(vec2.create(), this.viewBox.size, 0.5);
|
||||
|
||||
this.viewCircle.center = vec2.add(
|
||||
vec2.create(),
|
||||
this.viewBox.topLeft,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue