Some improvements

This commit is contained in:
schmelczerandras 2020-09-11 21:06:40 +02:00
parent 23a6b473ae
commit b1b3ca685a
20 changed files with 259 additions and 217 deletions

View file

@ -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';

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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,22 +30,25 @@ 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.bindTexture(this.gl.TEXTURE_2D, this.frameTexture);
this.gl.texImage2D(
this.gl.TEXTURE_2D,
0,
this.gl.RG16F,
this.size.x,
this.size.y,
0,
this.gl.RG,
this.gl.FLOAT,
null
);
}
this.gl.texImage2D(
this.gl.TEXTURE_2D,
0,
this.gl.RG16F,
this.size.x,
this.size.y,
0,
this.gl.RG,
this.gl.FLOAT,
null
);
return hasChanged;
}
private configureTexture() {

View file

@ -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;
};

View file

@ -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) {

View file

@ -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;

View file

@ -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;
});
}

View file

@ -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;
}

View file

@ -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(', ')
);
}
}

View file

@ -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 = [];
}
}

View file

@ -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 {

View file

@ -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: {

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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);
}
}