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