Some improvements
This commit is contained in:
parent
23a6b473ae
commit
b1b3ca685a
20 changed files with 259 additions and 217 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { waitWhileFalse } from '../../../helper/wait-for';
|
||||
import { waitWhileFalse } from '../../../helper/wait-while-false';
|
||||
import { tryEnableExtension } from '../helper/enable-extension';
|
||||
import { checkProgram } from './check-program';
|
||||
import { createShader } from './create-shader';
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ export class DefaultFrameBuffer extends FrameBuffer {
|
|||
constructor(gl: WebGL2RenderingContext) {
|
||||
super(gl);
|
||||
this.frameBuffer = null;
|
||||
|
||||
this.setSize();
|
||||
}
|
||||
|
||||
public setSize() {
|
||||
super.setSize();
|
||||
|
||||
if (this.gl.canvas.width !== this.size.x || this.gl.canvas.height !== this.size.y) {
|
||||
public setSize(): boolean {
|
||||
const hasChanged = super.setSize();
|
||||
if (hasChanged) {
|
||||
this.gl.canvas.width = this.size.x;
|
||||
this.gl.canvas.height = this.size.y;
|
||||
}
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { settings } from '../../settings';
|
||||
|
||||
export abstract class FrameBuffer {
|
||||
public renderScale = 1;
|
||||
public enableHighDpiRendering = settings.enableHighDpiRendering;
|
||||
|
||||
public enableHighDpiRendering = false;
|
||||
|
||||
protected size: vec2;
|
||||
|
||||
protected size = vec2.create();
|
||||
protected frameBuffer: WebGLFramebuffer;
|
||||
|
||||
constructor(protected gl: WebGL2RenderingContext) {}
|
||||
|
|
@ -23,15 +22,20 @@ export abstract class FrameBuffer {
|
|||
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public setSize() {
|
||||
const realToCssPixels = window.devicePixelRatio * this.renderScale;
|
||||
public setSize(): boolean {
|
||||
const realToCssPixels =
|
||||
(this.enableHighDpiRendering ? window.devicePixelRatio : 1) * this.renderScale;
|
||||
|
||||
const canvasWidth = (this.gl.canvas as HTMLCanvasElement).clientWidth;
|
||||
const canvasHeight = (this.gl.canvas as HTMLCanvasElement).clientHeight;
|
||||
|
||||
const displayWidth = Math.floor(canvasWidth * realToCssPixels);
|
||||
const displayHeight = Math.floor(canvasHeight * realToCssPixels);
|
||||
|
||||
const oldSize = vec2.clone(this.getSize());
|
||||
this.size = vec2.fromValues(displayWidth, displayHeight);
|
||||
|
||||
return this.size.x != oldSize.x || this.size.y != oldSize.y;
|
||||
}
|
||||
|
||||
public getSize(): vec2 {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { FrameBuffer } from './frame-buffer';
|
||||
import { enableExtension } from '../helper/enable-extension';
|
||||
import { FrameBuffer } from './frame-buffer';
|
||||
|
||||
export class IntermediateFrameBuffer extends FrameBuffer {
|
||||
private frameTexture: WebGLTexture;
|
||||
|
||||
private floatLinearEnabled = true;
|
||||
private floatLinearEnabled = false;
|
||||
|
||||
constructor(gl: WebGL2RenderingContext) {
|
||||
super(gl);
|
||||
|
|
@ -13,8 +12,9 @@ export class IntermediateFrameBuffer extends FrameBuffer {
|
|||
|
||||
try {
|
||||
enableExtension(gl, 'OES_texture_float_linear');
|
||||
this.floatLinearEnabled = true;
|
||||
} catch {
|
||||
this.floatLinearEnabled = false;
|
||||
// it's okay
|
||||
}
|
||||
|
||||
this.frameTexture = this.gl.createTexture();
|
||||
|
|
@ -30,9 +30,9 @@ export class IntermediateFrameBuffer extends FrameBuffer {
|
|||
return this.frameTexture;
|
||||
}
|
||||
|
||||
public setSize() {
|
||||
super.setSize();
|
||||
|
||||
public setSize(): boolean {
|
||||
const hasChanged = super.setSize();
|
||||
if (hasChanged) {
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture);
|
||||
|
||||
this.gl.texImage2D(
|
||||
|
|
@ -48,6 +48,9 @@ export class IntermediateFrameBuffer extends FrameBuffer {
|
|||
);
|
||||
}
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
private configureTexture() {
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture);
|
||||
this.gl.texParameteri(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
import { InfoText } from '../../../objects/types/info-text';
|
||||
|
||||
const extensions: Map<string, any> = new Map();
|
||||
|
||||
const printExtensions = () => {
|
||||
const values = {};
|
||||
for (const [k, v] of extensions.entries()) {
|
||||
values[k] = v !== null;
|
||||
}
|
||||
InfoText.modifyRecord('extensions', values);
|
||||
};
|
||||
|
||||
export const tryEnableExtension = (
|
||||
gl: WebGL2RenderingContext,
|
||||
name: string
|
||||
|
|
@ -15,6 +25,8 @@ export const tryEnableExtension = (
|
|||
|
||||
extensions.set(name, extension);
|
||||
|
||||
printExtensions();
|
||||
|
||||
return extension;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,8 @@ import { enableExtension } from './enable-extension';
|
|||
|
||||
export class WebGlStopwatch {
|
||||
private timerExtension: any;
|
||||
|
||||
private timerQuery: WebGLQuery;
|
||||
|
||||
private isReady = true;
|
||||
|
||||
private resultsInNanoSeconds: number;
|
||||
|
||||
constructor(private gl: WebGL2RenderingContext) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { vec2 } from 'gl-matrix';
|
|||
|
||||
export interface IProgram {
|
||||
initialize(): Promise<void>;
|
||||
setDrawingRectangle(bottomLeft: vec2, size: vec2): void;
|
||||
setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void;
|
||||
bindAndSetUniforms(values: { [name: string]: any }): void;
|
||||
draw(): void;
|
||||
delete(): void;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export default abstract class Program implements IProgram {
|
|||
protected program: WebGLProgram;
|
||||
private programPromise: Promise<WebGLProgram>;
|
||||
private modelTransform = mat2d.identity(mat2d.create());
|
||||
private readonly ndcToUv: mat2d;
|
||||
private readonly ndcToUv = mat2d.fromValues(0.5, 0, 0, 0.5, 0.5, 0.5);
|
||||
private uniforms: Array<{
|
||||
name: Array<string>;
|
||||
location: WebGLUniformLocation;
|
||||
|
|
@ -28,9 +28,6 @@ export default abstract class Program implements IProgram {
|
|||
fragmentShaderSource,
|
||||
substitutions
|
||||
);
|
||||
|
||||
this.ndcToUv = mat2d.fromScaling(mat2d.create(), vec2.fromValues(0.5, 0.5));
|
||||
mat2d.translate(this.ndcToUv, this.ndcToUv, vec2.fromValues(1, 1));
|
||||
}
|
||||
|
||||
public async initialize(): Promise<void> {
|
||||
|
|
@ -43,7 +40,7 @@ export default abstract class Program implements IProgram {
|
|||
this.setUniforms({ modelTransform: this.modelTransform, ...values });
|
||||
}
|
||||
|
||||
public setDrawingRectangle(bottomLeft: vec2, size: vec2) {
|
||||
public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) {
|
||||
mat2d.invert(this.modelTransform, this.ndcToUv);
|
||||
mat2d.translate(this.modelTransform, this.modelTransform, bottomLeft);
|
||||
mat2d.scale(this.modelTransform, this.modelTransform, size);
|
||||
|
|
@ -93,9 +90,11 @@ export default abstract class Program implements IProgram {
|
|||
this.uniforms.map((u1) => {
|
||||
const isSingle =
|
||||
this.uniforms.filter((u2) => u2.name.includes(u1.name[0])).length == 1;
|
||||
|
||||
if (u1.name.includes('0') && isSingle) {
|
||||
u1.name = u1.name.slice(0, -1);
|
||||
}
|
||||
|
||||
return u1;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class UniformArrayAutoScalingProgram implements IProgram {
|
|||
}> = [];
|
||||
|
||||
private current: FragmentShaderOnlyProgram;
|
||||
private drawingRectangleTopLeft = vec2.fromValues(0, 0);
|
||||
private drawingRectangleBottomLeft = vec2.fromValues(0, 0);
|
||||
private drawingRectangleSize = vec2.fromValues(1, 1);
|
||||
|
||||
constructor(
|
||||
|
|
@ -50,15 +50,15 @@ export class UniformArrayAutoScalingProgram implements IProgram {
|
|||
});
|
||||
}
|
||||
|
||||
this.current.setDrawingRectangle(
|
||||
this.drawingRectangleTopLeft,
|
||||
this.current.setDrawingRectangleUV(
|
||||
this.drawingRectangleBottomLeft,
|
||||
this.drawingRectangleSize
|
||||
);
|
||||
this.current.bindAndSetUniforms(uniforms);
|
||||
}
|
||||
|
||||
public setDrawingRectangle(topLeft: vec2, size: vec2) {
|
||||
this.drawingRectangleTopLeft = topLeft;
|
||||
public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) {
|
||||
this.drawingRectangleBottomLeft = bottomLeft;
|
||||
this.drawingRectangleSize = size;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
import { Autoscaler } from '../../helper/autoscaler';
|
||||
import { settings } from '../settings';
|
||||
import { Autoscaler as AutoScaler } from '../../helper/autoscaler';
|
||||
import { exponentialDecay } from '../../helper/exponential-decay';
|
||||
import { InfoText } from '../../objects/types/info-text';
|
||||
import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer';
|
||||
import { toPercent } from '../../helper/to-percent';
|
||||
import { settings } from '../settings';
|
||||
|
||||
export class FpsAutoscaler extends Autoscaler {
|
||||
export class FpsAutoscaler extends AutoScaler {
|
||||
private timeSinceLastAdjusment = 0;
|
||||
|
||||
private exponentialDecayedDeltaTime = 0.0;
|
||||
|
||||
constructor(private frameBuffers: Array<FrameBuffer>) {
|
||||
constructor(setters: { [key: string]: (value: number | boolean) => void }) {
|
||||
super(
|
||||
frameBuffers.map((f) => (v) => (f.renderScale = v)),
|
||||
settings.qualityScaling.scaleTargets,
|
||||
setters,
|
||||
settings.qualityScaling.qualityTargets,
|
||||
settings.qualityScaling.startingTargetIndex,
|
||||
settings.qualityScaling.scalingOptions
|
||||
);
|
||||
|
|
@ -45,10 +41,5 @@ export class FpsAutoscaler extends Autoscaler {
|
|||
this.decrease();
|
||||
}
|
||||
}
|
||||
|
||||
InfoText.modifyRecord(
|
||||
'quality',
|
||||
this.frameBuffers.map((f) => toPercent(f.renderScale)).join(', ')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { mat2d, vec2 } from 'gl-matrix';
|
||||
import { InfoText } from '../../objects/types/info-text';
|
||||
import { IDrawable } from '../drawables/i-drawable';
|
||||
import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor';
|
||||
import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer';
|
||||
|
|
@ -8,13 +7,12 @@ import { settings } from '../settings';
|
|||
|
||||
export class RenderingPass {
|
||||
private drawables: Array<IDrawable> = [];
|
||||
|
||||
private program: UniformArrayAutoScalingProgram;
|
||||
|
||||
constructor(
|
||||
gl: WebGL2RenderingContext,
|
||||
shaderSources: [string, string],
|
||||
private drawableDescriptors: Array<IDrawableDescriptor>,
|
||||
drawableDescriptors: Array<IDrawableDescriptor>,
|
||||
private frame: FrameBuffer
|
||||
) {
|
||||
this.program = new UniformArrayAutoScalingProgram(
|
||||
|
|
@ -39,38 +37,34 @@ export class RenderingPass {
|
|||
inputTexture?: WebGLTexture
|
||||
) {
|
||||
this.frame.bindAndClear(inputTexture);
|
||||
const q = 1 / settings.tileMultiplier;
|
||||
const tileUvSize = vec2.fromValues(q, q);
|
||||
|
||||
const origin = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.fromValues(0, 0),
|
||||
commonUniforms.uvToWorld
|
||||
);
|
||||
const stepsInUV = 1 / settings.tileMultiplier;
|
||||
|
||||
const firstCenter = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.fromValues(q, q),
|
||||
commonUniforms.uvToWorld
|
||||
);
|
||||
const worldR =
|
||||
0.5 *
|
||||
vec2.length(vec2.scale(vec2.create(), commonUniforms.worldAreaInView, stepsInUV));
|
||||
|
||||
vec2.subtract(firstCenter, firstCenter, origin);
|
||||
const stepsInNDC = 2 * stepsInUV;
|
||||
|
||||
const worldR = vec2.length(firstCenter);
|
||||
|
||||
let sumLineCount = 0;
|
||||
|
||||
for (let x = 0; x < 1; x += q) {
|
||||
for (let y = 0; y < 1; y += q) {
|
||||
for (let x = -1; x < 1; x += stepsInNDC) {
|
||||
for (let y = -1; y < 1; y += stepsInNDC) {
|
||||
const uniforms = { ...commonUniforms };
|
||||
uniforms.maxMinDistance = 2 * worldR * scale;
|
||||
|
||||
const uvBottomLeft = vec2.fromValues(x, y);
|
||||
this.program.setDrawingRectangle(uvBottomLeft, tileUvSize);
|
||||
const ndcBottomLeft = vec2.fromValues(x, y);
|
||||
|
||||
this.program.setDrawingRectangleUV(
|
||||
[(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2],
|
||||
vec2.fromValues(stepsInUV, stepsInUV)
|
||||
);
|
||||
|
||||
const tileCenterWorldCoordinates = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.add(vec2.create(), uvBottomLeft, vec2.fromValues(q, q)),
|
||||
vec2.add(
|
||||
vec2.create(),
|
||||
[(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2],
|
||||
vec2.fromValues(stepsInUV / 2, stepsInUV / 2)
|
||||
),
|
||||
uniforms.uvToWorld
|
||||
);
|
||||
|
||||
|
|
@ -78,8 +72,6 @@ export class RenderingPass {
|
|||
(d) => d.distance(tileCenterWorldCoordinates) < 2 * worldR
|
||||
);
|
||||
|
||||
sumLineCount += primitivesNearTile.length;
|
||||
|
||||
primitivesNearTile.forEach((p) =>
|
||||
p.serializeToUniforms(uniforms, scale, transform)
|
||||
);
|
||||
|
|
@ -89,16 +81,6 @@ export class RenderingPass {
|
|||
}
|
||||
}
|
||||
|
||||
InfoText.modifyRecord(
|
||||
`nearby ${this.drawableDescriptors[0].countMacroName}`,
|
||||
this.drawables.length.toFixed(2)
|
||||
);
|
||||
|
||||
InfoText.modifyRecord(
|
||||
`drawn ${this.drawableDescriptors[0].countMacroName}`,
|
||||
(sumLineCount / settings.tileMultiplier / settings.tileMultiplier).toFixed(2)
|
||||
);
|
||||
|
||||
this.drawables = [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,13 @@ export class WebGl2Renderer implements IRenderer {
|
|||
private gl: WebGL2RenderingContext;
|
||||
private stopwatch?: WebGlStopwatch;
|
||||
|
||||
private upscaleTransform = mat2d.create();
|
||||
private linearUpscale = 1;
|
||||
private scaleWorldToNDC = mat2d.create();
|
||||
private scaleWorldAreaInViewToNDC = 1;
|
||||
|
||||
private viewBoxBottomLeft = vec2.create();
|
||||
private viewBoxSize = vec2.create();
|
||||
private viewAreaScale: vec2;
|
||||
private viewAreaBottomLeft = vec2.create();
|
||||
private worldAreaInView = vec2.create();
|
||||
private squareToAspectRatio: vec2;
|
||||
private uvToWorld: mat2d;
|
||||
private cursorPosition = vec2.create();
|
||||
|
||||
private distanceFieldFrameBuffer: IntermediateFrameBuffer;
|
||||
|
|
@ -38,12 +39,7 @@ export class WebGl2Renderer implements IRenderer {
|
|||
|
||||
private initializePromise: Promise<[void, void]> = null;
|
||||
|
||||
private matrices: {
|
||||
distanceScreenToWorld?: mat2d;
|
||||
worldToDistanceUV?: mat2d;
|
||||
cursorPosition?: mat2d;
|
||||
uvToWorld?: mat2d;
|
||||
} = {};
|
||||
private softShadowsEnabled: boolean;
|
||||
|
||||
constructor(private canvas: HTMLCanvasElement, private overlay: HTMLElement) {
|
||||
this.gl = getWebGl2Context(canvas);
|
||||
|
|
@ -70,10 +66,12 @@ export class WebGl2Renderer implements IRenderer {
|
|||
this.lightingPass.initialize(),
|
||||
]);
|
||||
|
||||
this.autoscaler = new FpsAutoscaler([
|
||||
this.lightingFrameBuffer,
|
||||
this.distanceFieldFrameBuffer,
|
||||
]);
|
||||
this.autoscaler = new FpsAutoscaler({
|
||||
distanceRenderScale: (v) =>
|
||||
(this.distanceFieldFrameBuffer.renderScale = v as number),
|
||||
finalRenderScale: (v) => (this.lightingFrameBuffer.renderScale = v as number),
|
||||
softShadowsEnabled: (v) => (this.softShadowsEnabled = v as boolean),
|
||||
});
|
||||
|
||||
try {
|
||||
this.stopwatch = new WebGlStopwatch(this.gl);
|
||||
|
|
@ -106,11 +104,15 @@ export class WebGl2Renderer implements IRenderer {
|
|||
public finishFrame() {
|
||||
this.calculateMatrices();
|
||||
|
||||
this.distancePass.render(this.uniforms, this.linearUpscale, this.upscaleTransform);
|
||||
this.distancePass.render(
|
||||
this.uniforms,
|
||||
this.scaleWorldAreaInViewToNDC,
|
||||
this.scaleWorldToNDC
|
||||
);
|
||||
this.lightingPass.render(
|
||||
this.uniforms,
|
||||
this.linearUpscale,
|
||||
this.upscaleTransform,
|
||||
this.scaleWorldAreaInViewToNDC,
|
||||
this.scaleWorldToNDC,
|
||||
this.distanceFieldFrameBuffer.colorTexture
|
||||
);
|
||||
|
||||
|
|
@ -118,46 +120,37 @@ export class WebGl2Renderer implements IRenderer {
|
|||
}
|
||||
|
||||
private get uniforms(): any {
|
||||
const cursorPosition = this.screenUvToWorldCoordinate(this.cursorPosition);
|
||||
const cursorPosition = this.uvToWorldCoordinate(this.cursorPosition);
|
||||
return {
|
||||
...this.matrices,
|
||||
cursorPosition,
|
||||
viewAreaScale: this.viewAreaScale,
|
||||
pixelSize:
|
||||
(4.5 * this.scaleWorldAreaInViewToNDC) /
|
||||
this.distanceFieldFrameBuffer.renderScale,
|
||||
uvToWorld: this.uvToWorld,
|
||||
worldAreaInView: this.worldAreaInView,
|
||||
squareToAspectRatio: this.squareToAspectRatio,
|
||||
softShadowsEnabled: this.softShadowsEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
private calculateMatrices() {
|
||||
this.matrices.uvToWorld = mat2d.fromTranslation(
|
||||
mat2d.create(),
|
||||
this.viewBoxBottomLeft
|
||||
);
|
||||
mat2d.scale(this.matrices.uvToWorld, this.matrices.uvToWorld, this.viewBoxSize);
|
||||
|
||||
this.matrices.distanceScreenToWorld = this.getScreenToWorldTransform(
|
||||
this.distanceFieldFrameBuffer.getSize()
|
||||
);
|
||||
|
||||
this.matrices.worldToDistanceUV = mat2d.scale(
|
||||
mat2d.create(),
|
||||
this.matrices.distanceScreenToWorld,
|
||||
this.distanceFieldFrameBuffer.getSize()
|
||||
);
|
||||
mat2d.invert(this.matrices.worldToDistanceUV, this.matrices.worldToDistanceUV);
|
||||
this.uvToWorld = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft);
|
||||
mat2d.scale(this.uvToWorld, this.uvToWorld, this.worldAreaInView);
|
||||
}
|
||||
|
||||
private getScreenToWorldTransform(screenSize: vec2) {
|
||||
const transform = mat2d.fromTranslation(mat2d.create(), this.viewBoxBottomLeft);
|
||||
const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft);
|
||||
mat2d.scale(
|
||||
transform,
|
||||
transform,
|
||||
vec2.divide(vec2.create(), this.viewBoxSize, screenSize)
|
||||
vec2.divide(vec2.create(), this.worldAreaInView, screenSize)
|
||||
);
|
||||
mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5));
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
public screenUvToWorldCoordinate(screenUvPosition: vec2): vec2 {
|
||||
public uvToWorldCoordinate(screenUvPosition: vec2): vec2 {
|
||||
const resolution = vec2.fromValues(this.canvas.width, this.canvas.height);
|
||||
|
||||
return vec2.transformMat2d(
|
||||
|
|
@ -172,31 +165,36 @@ export class WebGl2Renderer implements IRenderer {
|
|||
}
|
||||
|
||||
public setViewArea(viewArea: BoundingBoxBase) {
|
||||
const targetRange = 2;
|
||||
this.worldAreaInView = viewArea.size;
|
||||
|
||||
this.viewBoxSize = viewArea.size;
|
||||
this.viewBoxBottomLeft = vec2.add(
|
||||
// world coordinates
|
||||
this.viewAreaBottomLeft = vec2.add(
|
||||
vec2.create(),
|
||||
viewArea.topLeft,
|
||||
vec2.fromValues(0, -viewArea.size.y)
|
||||
);
|
||||
|
||||
this.linearUpscale = targetRange / Math.max(this.viewBoxSize.x, this.viewBoxSize.y);
|
||||
const scaleLongerEdgeTo1 =
|
||||
1 / Math.max(this.worldAreaInView.x, this.worldAreaInView.y);
|
||||
|
||||
this.viewAreaScale = vec2.fromValues(
|
||||
(this.viewBoxSize.x * this.linearUpscale) / 2,
|
||||
(this.viewBoxSize.y * this.linearUpscale) / 2
|
||||
this.squareToAspectRatio = vec2.fromValues(
|
||||
this.worldAreaInView.x * scaleLongerEdgeTo1,
|
||||
this.worldAreaInView.y * scaleLongerEdgeTo1
|
||||
);
|
||||
|
||||
this.scaleWorldAreaInViewToNDC = scaleLongerEdgeTo1 * 2;
|
||||
|
||||
mat2d.fromScaling(
|
||||
this.upscaleTransform,
|
||||
vec2.fromValues(this.linearUpscale, this.linearUpscale)
|
||||
this.scaleWorldToNDC,
|
||||
vec2.fromValues(this.scaleWorldAreaInViewToNDC, this.scaleWorldAreaInViewToNDC)
|
||||
);
|
||||
|
||||
const translate = vec2.scale(vec2.create(), this.viewBoxBottomLeft, -1);
|
||||
vec2.subtract(translate, translate, vec2.scale(vec2.create(), this.viewBoxSize, 0.5));
|
||||
|
||||
mat2d.translate(this.upscaleTransform, this.upscaleTransform, translate);
|
||||
const translate = vec2.scale(vec2.create(), this.viewAreaBottomLeft, -1);
|
||||
vec2.subtract(
|
||||
translate,
|
||||
translate,
|
||||
vec2.scale(vec2.create(), this.worldAreaInView, 0.5)
|
||||
);
|
||||
mat2d.translate(this.scaleWorldToNDC, this.scaleWorldToNDC, translate);
|
||||
}
|
||||
|
||||
public setCursorPosition(position: vec2): void {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,51 @@
|
|||
export const settings = {
|
||||
enableHighDpiRendering: true,
|
||||
qualityScaling: {
|
||||
targetDeltaTimeInMilliseconds: 30,
|
||||
targetDeltaTimeInMilliseconds: 20,
|
||||
deltaTimeError: 2,
|
||||
deltaTimeResponsiveness: 1 / 16,
|
||||
adjusmentRateInMilliseconds: 300,
|
||||
scaleTargets: [
|
||||
[0.2, 0.1],
|
||||
[0.6, 0.1],
|
||||
[1, 1],
|
||||
/*[1.25, 0.75],
|
||||
[1.5, 1],
|
||||
[1.75, 1.25],
|
||||
//[1.75, 1.75],
|
||||
//[2, 2],*/
|
||||
qualityTargets: [
|
||||
{
|
||||
distanceRenderScale: 0.1,
|
||||
finalRenderScale: 0.2,
|
||||
softShadowsEnabled: false,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 0.1,
|
||||
finalRenderScale: 0.6,
|
||||
softShadowsEnabled: false,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 0.2,
|
||||
finalRenderScale: 1.0,
|
||||
softShadowsEnabled: false,
|
||||
},
|
||||
/* {
|
||||
distanceRenderScale: 0.3,
|
||||
finalRenderScale: 1.0,
|
||||
softShadowsEnabled: true,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 1.0,
|
||||
finalRenderScale: 1.25,
|
||||
softShadowsEnabled: true,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 1.0,
|
||||
finalRenderScale: 1.5,
|
||||
softShadowsEnabled: true,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 1.25,
|
||||
finalRenderScale: 1.75,
|
||||
softShadowsEnabled: true,
|
||||
},
|
||||
{
|
||||
distanceRenderScale: 2,
|
||||
finalRenderScale: 2,
|
||||
softShadowsEnabled: true,
|
||||
},*/
|
||||
],
|
||||
startingTargetIndex: 2,
|
||||
scalingOptions: {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
precision lowp float;
|
||||
|
||||
#define LINE_COUNT {lineCount}
|
||||
#define BLOB_COUNT {blobCount}
|
||||
|
||||
uniform float maxMinDistance;
|
||||
uniform float pixelSize;
|
||||
|
||||
in vec2 position;
|
||||
|
||||
|
||||
#if LINE_COUNT > 0
|
||||
uniform struct {
|
||||
vec2 from;
|
||||
|
|
@ -19,7 +19,7 @@ in vec2 position;
|
|||
}[LINE_COUNT] lines;
|
||||
|
||||
void lineMinDistance(inout float minDistance, inout float color) {
|
||||
float myMinDistance = 10.0;
|
||||
float myMinDistance = maxMinDistance;
|
||||
for (int i = 0; i < LINE_COUNT; i++) {
|
||||
vec2 targetFromDelta = position - lines[i].from;
|
||||
vec2 toFromDelta = lines[i].toFromDelta;
|
||||
|
|
@ -35,10 +35,11 @@ in vec2 position;
|
|||
targetFromDelta, toFromDelta * h
|
||||
);
|
||||
|
||||
color = mix(1.0, color, step(0.0, lineDistance));
|
||||
myMinDistance = min(myMinDistance, lineDistance);
|
||||
}
|
||||
|
||||
color = mix(0.0, color, step(pixelSize, -myMinDistance));
|
||||
|
||||
minDistance = -myMinDistance;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -67,7 +68,7 @@ in vec2 position;
|
|||
res += exp2(-blobs[i].k * circleMinDistance(blobs[i].rightFootCenter, blobs[i].footRadius));
|
||||
res = -log2(res) / blobs[i].k;
|
||||
|
||||
color = mix(2.0, color, step(0.0, res));
|
||||
color = mix(1.0, color, step(pixelSize, res));
|
||||
|
||||
minDistance = min(minDistance, res);
|
||||
}
|
||||
|
|
@ -77,7 +78,7 @@ in vec2 position;
|
|||
out vec2 fragmentColor;
|
||||
|
||||
void main() {
|
||||
float minDistance = -10.0;
|
||||
float minDistance = -maxMinDistance;
|
||||
float color = 0.0;
|
||||
|
||||
#if LINE_COUNT > 0
|
||||
|
|
@ -86,6 +87,8 @@ void main() {
|
|||
|
||||
#if BLOB_COUNT > 0
|
||||
blobMinDistance(minDistance, color);
|
||||
//fragmentColor = vec2(-1.0, 2.0);
|
||||
//return;
|
||||
#endif
|
||||
|
||||
fragmentColor = vec2(minDistance, color);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
precision lowp float;
|
||||
|
||||
#define INFINITY 1000.0
|
||||
#define LIGHT_DROP 0.25
|
||||
#define AMBIENT_LIGHT vec3(0.3)
|
||||
#define SOFT_SHADOWS_QUALITY 2.0
|
||||
#define AMBIENT_LIGHT vec3(0.75)
|
||||
|
||||
#define CIRCLE_LIGHT_COUNT {circleLightCount}
|
||||
#define POINT_LIGHT_COUNT {pointLightCount}
|
||||
|
||||
#define SOFT_SHADOWS_ENABLED 1
|
||||
#define HARD_SHADOWS_QUALITY 1.5
|
||||
#define SOFT_SHADOWS_QUALITY 2.0
|
||||
uniform bool softShadowsEnabled;
|
||||
|
||||
#define AIR_COLOR vec3(0.4)
|
||||
|
||||
uniform sampler2D distanceTexture;
|
||||
|
||||
vec3[4] colors = vec3[4](
|
||||
vec3(0.2),
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
vec3[3] colors = vec3[](
|
||||
vec3(0.1, 0.05, 0.15),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
float getDistance(in vec2 target, out vec3 color) {
|
||||
float getDistance(in vec2 target, out vec3 color, out float nearness) {
|
||||
vec4 values = texture(distanceTexture, target);
|
||||
color = colors[int(values[1])];
|
||||
|
||||
|
|
@ -56,13 +56,21 @@ float getDistance(in vec2 target) {
|
|||
|
||||
in vec2 position;
|
||||
in vec2 uvCoordinates;
|
||||
uniform vec2 viewAreaScale;
|
||||
uniform vec2 squareToAspectRatio;
|
||||
|
||||
out vec4 fragmentColor;
|
||||
|
||||
void main() {
|
||||
vec3 colorAtPosition;
|
||||
float startingDistance = getDistance(uvCoordinates, colorAtPosition);
|
||||
float nearness;
|
||||
float startingDistance = getDistance(uvCoordinates, colorAtPosition, nearness);
|
||||
if (startingDistance < 0.0) {
|
||||
fragmentColor = vec4(colorAtPosition, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
colorAtPosition = AIR_COLOR;
|
||||
|
||||
vec3 lighting = AMBIENT_LIGHT;
|
||||
|
||||
#if CIRCLE_LIGHT_COUNT > 0
|
||||
|
|
@ -71,18 +79,14 @@ void main() {
|
|||
float lightDistance = lightCenterDistance - circleLights[i].radius;
|
||||
float traceDistance = lightCenterDistance - circleLights[i].traceRadius;
|
||||
|
||||
if (traceDistance < 0.0) {
|
||||
lighting = vec3(1.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
vec3 lightColorAtPosition = circleLights[i].value / pow(
|
||||
lightDistance / LIGHT_DROP + 1.0, 2.0
|
||||
);
|
||||
|
||||
#if SOFT_SHADOWS_ENABLED
|
||||
if (softShadowsEnabled) {
|
||||
float q = INFINITY;
|
||||
float rayLength = startingDistance / SOFT_SHADOWS_QUALITY;
|
||||
vec2 direction = normalize(circleLightDirections[i]) / viewAreaScale / 2.0;
|
||||
vec2 direction = normalize(circleLightDirections[i]) / squareToAspectRatio / 2.05;
|
||||
for (int j = 0; j < 48 * int(ceil(SOFT_SHADOWS_QUALITY)); j++) {
|
||||
if (rayLength >= traceDistance) {
|
||||
lighting += lightColorAtPosition * clamp(
|
||||
|
|
@ -96,20 +100,17 @@ void main() {
|
|||
q = min(q, minDistance / rayLength);
|
||||
rayLength += minDistance / SOFT_SHADOWS_QUALITY;
|
||||
}
|
||||
#else
|
||||
float rayLength = startingDistance / 2.0;
|
||||
vec2 direction = normalize(circleLightDirections[i]) / viewAreaScale / 2.0;
|
||||
for (int j = 0; j < 24 * int(ceil(HARD_SHADOWS_QUALITY)); j++) {
|
||||
float minDistance = getDistance(uvCoordinates + direction * rayLength);
|
||||
if (minDistance < 0.0) {
|
||||
break;
|
||||
}
|
||||
rayLength += minDistance / HARD_SHADOWS_QUALITY;
|
||||
} else {
|
||||
float rayLength = startingDistance;
|
||||
vec2 direction = normalize(circleLightDirections[i]) / squareToAspectRatio / 2.05;
|
||||
for (int j = 0; j < 24; j++) {
|
||||
float currentDistance = getDistance(uvCoordinates + direction * rayLength);
|
||||
rayLength += currentDistance;
|
||||
}
|
||||
if (rayLength >= traceDistance) {
|
||||
lighting += lightColorAtPosition * step(0.0, startingDistance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -143,15 +144,5 @@ void main() {
|
|||
}*/
|
||||
#endif
|
||||
|
||||
|
||||
float d = startingDistance;
|
||||
vec3 col = (d<0.0) ? vec3(0.6,0.8,1.0) : vec3(0.9,0.6,0.3);
|
||||
col *= 1.0 - exp(-9.0*abs(d));
|
||||
col *= 1.0 + 0.2*cos(128.0*abs(d));
|
||||
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.015,abs(d)) );
|
||||
fragmentColor = vec4(col, 1.0);
|
||||
fragmentColor = vec4(colorAtPosition * lighting, 1.0);
|
||||
fragmentColor = vec4(mix(colorAtPosition * lighting, col, 0.2), 1.0);
|
||||
|
||||
//fragmentColor = vec4(vec3(startingDistance), 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
precision lowp float;
|
||||
|
||||
uniform mat3 modelTransform;
|
||||
uniform vec2 viewAreaScale;
|
||||
uniform vec2 squareToAspectRatio;
|
||||
|
||||
in vec4 vertexPosition;
|
||||
out vec2 position;
|
||||
|
|
@ -11,5 +11,5 @@ out vec2 position;
|
|||
void main() {
|
||||
vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform;
|
||||
gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0);
|
||||
position = vertexPosition2D.xy * viewAreaScale;
|
||||
position = vertexPosition2D.xy * squareToAspectRatio;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
precision lowp float;
|
||||
|
||||
#define CIRCLE_LIGHT_COUNT {circleLightCount}
|
||||
#define POINT_LIGHT_COUNT {pointLightCount}
|
||||
|
|
@ -11,7 +11,7 @@ in vec4 vertexPosition;
|
|||
out vec2 position;
|
||||
out vec2 uvCoordinates;
|
||||
|
||||
uniform vec2 viewAreaScale;
|
||||
uniform vec2 squareToAspectRatio;
|
||||
|
||||
#if CIRCLE_LIGHT_COUNT > 0
|
||||
uniform struct {
|
||||
|
|
@ -37,7 +37,7 @@ uniform vec2 viewAreaScale;
|
|||
void main() {
|
||||
vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform;
|
||||
gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0);
|
||||
position = vertexPosition2D.xy * viewAreaScale;
|
||||
position = vertexPosition2D.xy * squareToAspectRatio;
|
||||
|
||||
uvCoordinates = (vertexPosition2D * mat3(
|
||||
0.5, 0.0, 0.5,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { mix } from './mix';
|
||||
import { InfoText } from '../objects/types/info-text';
|
||||
import { clamp } from './clamp';
|
||||
import { mix } from './mix';
|
||||
|
||||
export class Autoscaler {
|
||||
// can have fractions
|
||||
private index: number;
|
||||
|
||||
constructor(
|
||||
private setters: Array<(value: number) => void>,
|
||||
private targets: Array<Array<number>>,
|
||||
private setters: { [key: string]: (value: number | boolean) => void },
|
||||
private targets: Array<{ [key: string]: number | boolean }>,
|
||||
startingIndex: number,
|
||||
private scalingOptions: {
|
||||
additiveIncrease: number;
|
||||
|
|
@ -38,8 +39,22 @@ export class Autoscaler {
|
|||
const nextTarget =
|
||||
floor + 1 == this.targets.length ? previousTarget : this.targets[floor + 1];
|
||||
|
||||
this.setters.forEach((setter, i) =>
|
||||
setter(mix(previousTarget[i], nextTarget[i], fract))
|
||||
);
|
||||
const result = {};
|
||||
for (const key in this.setters) {
|
||||
const previous = previousTarget[key];
|
||||
const next = nextTarget[key];
|
||||
let current: number | boolean;
|
||||
if (typeof previous == 'number') {
|
||||
current = mix(previous, next as number, fract);
|
||||
} else {
|
||||
current = next;
|
||||
}
|
||||
|
||||
result[key] = current;
|
||||
|
||||
this.setters[key](current);
|
||||
}
|
||||
|
||||
InfoText.modifyRecord('quality', result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { RenderCommand } from '../../drawing/commands/render';
|
|||
import { GameObject } from '../game-object';
|
||||
|
||||
export class InfoText extends GameObject {
|
||||
private static MinRowLength = 60;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
|
|
@ -10,13 +12,25 @@ export class InfoText extends GameObject {
|
|||
|
||||
private static records: Map<string, string> = new Map();
|
||||
|
||||
public static modifyRecord(key: string, value: string) {
|
||||
public static modifyRecord(key: string, value: string | any) {
|
||||
if (typeof value == 'string') {
|
||||
value = ' ' + value;
|
||||
} else {
|
||||
value = JSON.stringify(
|
||||
value,
|
||||
(_, v) => (v.toFixed ? Number(v.toFixed(2)) : v),
|
||||
' '
|
||||
);
|
||||
}
|
||||
|
||||
InfoText.records.set(key, value);
|
||||
}
|
||||
|
||||
private draw(e: RenderCommand) {
|
||||
let text = '';
|
||||
InfoText.records.forEach((v, k) => (text += `${k}\n\t${v}\n`));
|
||||
InfoText.records.forEach(
|
||||
(v, k) => (text += `${k}\n${v.padEnd(InfoText.MinRowLength)}\n`)
|
||||
);
|
||||
e.renderer.drawInfoText(text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue