Fix lights
This commit is contained in:
parent
13843f87a8
commit
e44be0c5ee
17 changed files with 179 additions and 117 deletions
|
|
@ -5,7 +5,7 @@ export abstract class Drawable {
|
|||
// This should be overriden by inherited classes
|
||||
public static readonly descriptor: DrawableDescriptor;
|
||||
|
||||
public abstract distance(target: vec2): number;
|
||||
public abstract minDistance(target: vec2): number;
|
||||
|
||||
protected abstract getObjectToSerialize(transform2d: mat2d, transform1d: number): any;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { mat2d, vec2, vec3 } from 'gl-matrix';
|
||||
import { Drawable } from '../drawable';
|
||||
import { vec2, vec3 } from 'gl-matrix';
|
||||
import { DrawableDescriptor } from '../drawable-descriptor';
|
||||
import { LightDrawable } from './light-drawable';
|
||||
|
||||
export class CircleLight extends Drawable {
|
||||
export class CircleLight extends LightDrawable {
|
||||
public static readonly descriptor: DrawableDescriptor = {
|
||||
uniformName: 'circleLights',
|
||||
uniformCountMacroName: 'CIRCLE_LIGHT_COUNT',
|
||||
|
|
@ -10,19 +10,7 @@ export class CircleLight extends Drawable {
|
|||
empty: new CircleLight(vec2.fromValues(0, 0), vec3.fromValues(0, 0, 0), 0),
|
||||
};
|
||||
|
||||
constructor(public center: vec2, public color: vec3, public intensity: number) {
|
||||
super();
|
||||
}
|
||||
|
||||
public distance(target: vec2): number {
|
||||
return vec2.dist(this.center, target);
|
||||
}
|
||||
|
||||
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
|
||||
return {
|
||||
center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
|
||||
color: this.color,
|
||||
intensity: this.intensity,
|
||||
};
|
||||
constructor(center: vec2, color: vec3, intensity: number) {
|
||||
super(center, color, intensity);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,33 @@
|
|||
import { mat2d, vec2, vec3 } from 'gl-matrix';
|
||||
import { Drawable } from '../drawable';
|
||||
import { DrawableDescriptor } from '../drawable-descriptor';
|
||||
import { LightDrawable } from './light-drawable';
|
||||
|
||||
export class Flashlight extends Drawable {
|
||||
export class Flashlight extends LightDrawable {
|
||||
public static readonly descriptor: DrawableDescriptor = {
|
||||
uniformName: 'flashlights',
|
||||
uniformCountMacroName: 'FLASHLIGHT_COUNT',
|
||||
shaderCombinationSteps: [0, 1, 2, 4],
|
||||
empty: new Flashlight(
|
||||
vec2.fromValues(0, 0),
|
||||
vec2.fromValues(0, 0),
|
||||
vec3.fromValues(0, 0, 0),
|
||||
0
|
||||
0,
|
||||
vec2.fromValues(0, 0)
|
||||
),
|
||||
};
|
||||
|
||||
public constructor(
|
||||
public center: vec2,
|
||||
public direction: vec2,
|
||||
public color: vec3,
|
||||
public intensity: number
|
||||
center: vec2,
|
||||
color: vec3,
|
||||
intensity: number,
|
||||
public direction: vec2
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public distance(_: vec2): number {
|
||||
return 0;
|
||||
super(center, color, intensity);
|
||||
}
|
||||
|
||||
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
|
||||
return {
|
||||
center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
|
||||
...super.getObjectToSerialize(transform2d, transform1d),
|
||||
direction: this.direction,
|
||||
intensity: this.intensity,
|
||||
color: this.color,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
src/drawables/lights/light-drawable.ts
Normal file
26
src/drawables/lights/light-drawable.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { mat2d, vec2, vec3 } from 'gl-matrix';
|
||||
import { Drawable } from '../../main';
|
||||
|
||||
export class LightDrawable extends Drawable {
|
||||
protected lightnessRatio = 1;
|
||||
|
||||
constructor(public center: vec2, public color: vec3, public intensity: number) {
|
||||
super();
|
||||
}
|
||||
|
||||
public setLightnessRatio(ratio: number) {
|
||||
this.lightnessRatio = ratio;
|
||||
}
|
||||
|
||||
public minDistance(target: vec2): number {
|
||||
return vec2.dist(this.center, target);
|
||||
}
|
||||
|
||||
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
|
||||
return {
|
||||
center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
|
||||
color: this.color,
|
||||
intensity: this.intensity * this.lightnessRatio,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ export class Circle extends Drawable {
|
|||
super();
|
||||
}
|
||||
|
||||
public distance(target: vec2): number {
|
||||
public minDistance(target: vec2): number {
|
||||
return vec2.dist(this.center, target) - this.radius;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export class InvertedTunnel extends Drawable {
|
|||
super();
|
||||
}
|
||||
|
||||
public distance(target: vec2): number {
|
||||
public minDistance(target: vec2): number {
|
||||
const toFromDelta = vec2.subtract(vec2.create(), this.to, this.from);
|
||||
const targetFromDelta = vec2.subtract(vec2.create(), target, this.from);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export class Tunnel extends Drawable {
|
|||
super();
|
||||
}
|
||||
|
||||
public distance(target: vec2): number {
|
||||
public minDistance(target: vec2): number {
|
||||
const toFromDelta = vec2.subtract(vec2.create(), this.to, this.from);
|
||||
const targetFromDelta = vec2.subtract(vec2.create(), target, this.from);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,13 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Drawable } from '../../drawables/drawable';
|
||||
import { DrawableDescriptor } from '../../drawables/drawable-descriptor';
|
||||
import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer';
|
||||
import { UniformArrayAutoScalingProgram } from '../graphics-library/program/uniform-array-autoscaling-program';
|
||||
import { Insights } from './insights';
|
||||
import { RenderingPassName } from './rendering-pass-name';
|
||||
import { Drawable } from '../../../drawables/drawable';
|
||||
import { Insights } from '../insights';
|
||||
import { RenderPass } from './render-pass';
|
||||
|
||||
export class RenderingPass {
|
||||
export class DistanceRenderPass extends RenderPass {
|
||||
public tileMultiplier = 8;
|
||||
public isWorldInverted = false;
|
||||
|
||||
private drawables: Array<Drawable> = [];
|
||||
private program: UniformArrayAutoScalingProgram;
|
||||
|
||||
constructor(
|
||||
gl: WebGL2RenderingContext,
|
||||
private frame: FrameBuffer,
|
||||
private name: RenderingPassName
|
||||
) {
|
||||
this.program = new UniformArrayAutoScalingProgram(gl);
|
||||
}
|
||||
|
||||
public async initialize(
|
||||
shaderSources: [string, string],
|
||||
descriptors: Array<DrawableDescriptor>,
|
||||
substitutions: { [name: string]: any } = {}
|
||||
): Promise<void> {
|
||||
await this.program.initialize(shaderSources, descriptors, substitutions);
|
||||
}
|
||||
|
||||
public addDrawable(drawable: Drawable) {
|
||||
this.drawables.push(drawable);
|
||||
|
|
@ -72,7 +52,7 @@ export class RenderingPass {
|
|||
);
|
||||
|
||||
const drawablesNearTile = this.drawables.filter(
|
||||
(d) => d.distance(tileCenterWorldCoordinates) < 2 * worldR
|
||||
(d) => d.minDistance(tileCenterWorldCoordinates) < 2 * worldR
|
||||
);
|
||||
|
||||
drawnDrawablesCount += drawablesNearTile.length;
|
||||
|
|
@ -89,18 +69,19 @@ export class RenderingPass {
|
|||
}
|
||||
}
|
||||
|
||||
Insights.setValue(['render pass', this.name, 'all drawables'], this.drawables.length);
|
||||
Insights.setValue(['render pass', this.name, 'tile count'], this.tileMultiplier ** 2);
|
||||
Insights.setValue(
|
||||
['render pass', this.name, 'rendered drawables'],
|
||||
['render pass', 'distance', 'all drawables'],
|
||||
this.drawables.length
|
||||
);
|
||||
Insights.setValue(
|
||||
['render pass', 'distance', 'tile count'],
|
||||
this.tileMultiplier ** 2
|
||||
);
|
||||
Insights.setValue(
|
||||
['render pass', 'distance', 'rendered drawables'],
|
||||
drawnDrawablesCount / this.tileMultiplier ** 2
|
||||
);
|
||||
|
||||
this.drawables = [];
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.frame.destroy();
|
||||
this.program.destroy();
|
||||
}
|
||||
}
|
||||
58
src/graphics/rendering/render-pass/lights-render-pass.ts
Normal file
58
src/graphics/rendering/render-pass/lights-render-pass.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { LightDrawable } from '../../../drawables/lights/light-drawable';
|
||||
import { clamp01 } from '../../../helper/clamp';
|
||||
import { Insights } from '../insights';
|
||||
import { RenderPass } from './render-pass';
|
||||
|
||||
export class LightsRenderPass extends RenderPass {
|
||||
public lightPhaseOutLength = 400;
|
||||
private drawables: Array<LightDrawable> = [];
|
||||
|
||||
public addDrawable(drawable: LightDrawable) {
|
||||
this.drawables.push(drawable);
|
||||
}
|
||||
|
||||
public render(commonUniforms: any, inputTexture?: WebGLTexture) {
|
||||
this.frame.bindAndClear(inputTexture);
|
||||
|
||||
const tileCenterWorldCoordinates = vec2.transformMat2d(
|
||||
vec2.create(),
|
||||
vec2.fromValues(0.5, 0.5),
|
||||
commonUniforms.uvToWorld
|
||||
);
|
||||
|
||||
const drawablesNearTile = this.drawables.filter((l) => {
|
||||
const d = vec2.subtract(
|
||||
vec2.create(),
|
||||
[
|
||||
Math.abs(l.center.x - tileCenterWorldCoordinates.x),
|
||||
Math.abs(l.center.y - tileCenterWorldCoordinates.y),
|
||||
],
|
||||
vec2.scale(vec2.create(), commonUniforms.worldAreaInView, 0.5)
|
||||
);
|
||||
const distance =
|
||||
vec2.length([Math.max(d.x, 0), Math.max(d.y, 0)]) +
|
||||
Math.min(Math.max(d.x, d.y), 0.0);
|
||||
l.setLightnessRatio(clamp01(1 - distance / this.lightPhaseOutLength));
|
||||
|
||||
return distance < this.lightPhaseOutLength;
|
||||
});
|
||||
|
||||
drawablesNearTile.forEach((p) =>
|
||||
p.serializeToUniforms(
|
||||
commonUniforms,
|
||||
commonUniforms.transformWorldToNDC,
|
||||
commonUniforms.scaleWorldLengthToNDC
|
||||
)
|
||||
);
|
||||
|
||||
this.program.draw(commonUniforms);
|
||||
|
||||
Insights.setValue(
|
||||
['render pass', 'lights', 'rendered drawables'],
|
||||
drawablesNearTile.length
|
||||
);
|
||||
|
||||
this.drawables = [];
|
||||
}
|
||||
}
|
||||
26
src/graphics/rendering/render-pass/render-pass.ts
Normal file
26
src/graphics/rendering/render-pass/render-pass.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { DrawableDescriptor } from '../../../drawables/drawable-descriptor';
|
||||
import { FrameBuffer } from '../../graphics-library/frame-buffer/frame-buffer';
|
||||
import { UniformArrayAutoScalingProgram } from '../../graphics-library/program/uniform-array-autoscaling-program';
|
||||
|
||||
export abstract class RenderPass {
|
||||
protected program: UniformArrayAutoScalingProgram;
|
||||
|
||||
constructor(gl: WebGL2RenderingContext, protected frame: FrameBuffer) {
|
||||
this.program = new UniformArrayAutoScalingProgram(gl);
|
||||
}
|
||||
|
||||
public async initialize(
|
||||
shaderSources: [string, string],
|
||||
descriptors: Array<DrawableDescriptor>,
|
||||
substitutions: { [name: string]: any } = {}
|
||||
): Promise<void> {
|
||||
await this.program.initialize(shaderSources, descriptors, substitutions);
|
||||
}
|
||||
|
||||
public abstract render(commonUniforms: any, inputTexture?: WebGLTexture): void;
|
||||
|
||||
public destroy(): void {
|
||||
this.frame.destroy();
|
||||
this.program.destroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
export enum RenderingPassName {
|
||||
distance = 'distance',
|
||||
pixel = 'pixel',
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { vec2, vec3 } from 'gl-matrix';
|
||||
import { Drawable } from '../../drawables/drawable';
|
||||
import { DrawableDescriptor } from '../../drawables/drawable-descriptor';
|
||||
import { LightDrawable } from '../../drawables/lights/light-drawable';
|
||||
import { msToString } from '../../helper/ms-to-string';
|
||||
import { DefaultFrameBuffer } from '../graphics-library/frame-buffer/default-frame-buffer';
|
||||
import { IntermediateFrameBuffer } from '../graphics-library/frame-buffer/intermediate-frame-buffer';
|
||||
|
|
@ -9,9 +10,9 @@ import { WebGlStopwatch } from '../graphics-library/helper/stopwatch';
|
|||
import { ParallelCompiler } from '../graphics-library/parallel-compiler';
|
||||
import { FpsAutoscaler } from './fps-autoscaler';
|
||||
import { Insights } from './insights';
|
||||
import { DistanceRenderPass } from './render-pass/distance-render-pass';
|
||||
import { LightsRenderPass } from './render-pass/lights-render-pass';
|
||||
import { Renderer } from './renderer';
|
||||
import { RenderingPass } from './rendering-pass';
|
||||
import { RenderingPassName } from './rendering-pass-name';
|
||||
import { RuntimeSettings } from './settings/runtime-settings';
|
||||
import { StartupSettings } from './settings/startup-settings';
|
||||
import distanceFragmentShader from './shaders/distance-fs.glsl';
|
||||
|
|
@ -20,15 +21,14 @@ import lightsFragmentShader from './shaders/shading-fs.glsl';
|
|||
import lightsVertexShader from './shaders/shading-vs.glsl';
|
||||
import { UniformsProvider } from './uniforms-provider';
|
||||
|
||||
type Passes = { [key in keyof typeof RenderingPassName]: RenderingPass };
|
||||
|
||||
export class WebGl2Renderer implements Renderer {
|
||||
private gl: WebGL2RenderingContext;
|
||||
private stopwatch?: WebGlStopwatch;
|
||||
private uniformsProvider: UniformsProvider;
|
||||
private distanceFieldFrameBuffer: IntermediateFrameBuffer;
|
||||
private distancePass: DistanceRenderPass;
|
||||
private lightsPass: LightsRenderPass;
|
||||
private lightingFrameBuffer: DefaultFrameBuffer;
|
||||
private passes: Passes;
|
||||
private autoscaler: FpsAutoscaler;
|
||||
|
||||
private applyRuntimeSettings: {
|
||||
|
|
@ -39,12 +39,10 @@ export class WebGl2Renderer implements Renderer {
|
|||
this.lightingFrameBuffer.enableHighDpiRendering = v;
|
||||
},
|
||||
tileMultiplier: (v) => {
|
||||
this.passes[RenderingPassName.distance].tileMultiplier = v;
|
||||
this.passes[RenderingPassName.pixel].tileMultiplier = 1;
|
||||
this.distancePass.tileMultiplier = v;
|
||||
},
|
||||
isWorldInverted: (v) => {
|
||||
this.passes[RenderingPassName.distance].isWorldInverted = v;
|
||||
this.passes[RenderingPassName.pixel].isWorldInverted = v;
|
||||
this.distancePass.isWorldInverted = v;
|
||||
},
|
||||
shadowLength: (v) => {
|
||||
this.uniformsProvider.shadowLength = v;
|
||||
|
|
@ -75,9 +73,8 @@ export class WebGl2Renderer implements Renderer {
|
|||
this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl);
|
||||
this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl);
|
||||
|
||||
this.passes = this.createPasses();
|
||||
|
||||
this.passes.pixel.tileMultiplier = 1;
|
||||
this.distancePass = new DistanceRenderPass(this.gl, this.distanceFieldFrameBuffer);
|
||||
this.lightsPass = new LightsRenderPass(this.gl, this.lightingFrameBuffer);
|
||||
|
||||
this.uniformsProvider = new UniformsProvider(this.gl);
|
||||
|
||||
|
|
@ -88,21 +85,6 @@ export class WebGl2Renderer implements Renderer {
|
|||
});
|
||||
}
|
||||
|
||||
private createPasses(): Passes {
|
||||
return {
|
||||
[RenderingPassName.distance]: new RenderingPass(
|
||||
this.gl,
|
||||
this.distanceFieldFrameBuffer,
|
||||
RenderingPassName.distance
|
||||
),
|
||||
[RenderingPassName.pixel]: new RenderingPass(
|
||||
this.gl,
|
||||
this.lightingFrameBuffer,
|
||||
RenderingPassName.pixel
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
public async initialize(
|
||||
palette: Array<vec3>,
|
||||
settingsOverrides: Partial<StartupSettings>
|
||||
|
|
@ -112,14 +94,14 @@ export class WebGl2Renderer implements Renderer {
|
|||
const promises: Array<Promise<void>> = [];
|
||||
|
||||
promises.push(
|
||||
this.passes[RenderingPassName.distance].initialize(
|
||||
this.distancePass.initialize(
|
||||
[distanceVertexShader, distanceFragmentShader],
|
||||
this.descriptors.filter(WebGl2Renderer.hasSdf)
|
||||
)
|
||||
);
|
||||
|
||||
promises.push(
|
||||
this.passes[RenderingPassName.pixel].initialize(
|
||||
this.lightsPass.initialize(
|
||||
[lightsVertexShader, lightsFragmentShader],
|
||||
this.descriptors.filter((d) => !WebGl2Renderer.hasSdf(d)),
|
||||
{
|
||||
|
|
@ -150,9 +132,9 @@ export class WebGl2Renderer implements Renderer {
|
|||
|
||||
public addDrawable(drawable: Drawable): void {
|
||||
if (WebGl2Renderer.hasSdf((drawable.constructor as typeof Drawable).descriptor)) {
|
||||
this.passes[RenderingPassName.distance].addDrawable(drawable);
|
||||
this.distancePass.addDrawable(drawable);
|
||||
} else {
|
||||
this.passes[RenderingPassName.pixel].addDrawable(drawable);
|
||||
this.lightsPass.addDrawable(drawable as LightDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,10 +175,8 @@ export class WebGl2Renderer implements Renderer {
|
|||
shadingNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()),
|
||||
};
|
||||
|
||||
this.passes[RenderingPassName.distance].render(
|
||||
this.uniformsProvider.getUniforms(common)
|
||||
);
|
||||
this.passes[RenderingPassName.pixel].render(
|
||||
this.distancePass.render(this.uniformsProvider.getUniforms(common));
|
||||
this.lightsPass.render(
|
||||
this.uniformsProvider.getUniforms(common),
|
||||
this.distanceFieldFrameBuffer.colorTexture
|
||||
);
|
||||
|
|
@ -219,7 +199,7 @@ export class WebGl2Renderer implements Renderer {
|
|||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.passes.distance.destroy();
|
||||
this.passes.pixel.destroy();
|
||||
this.distancePass.destroy();
|
||||
this.lightsPass.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Renderer } from './graphics/rendering/renderer';
|
|||
import { StartupSettings } from './graphics/rendering/settings/startup-settings';
|
||||
import { WebGl2Renderer } from './graphics/rendering/webgl2-renderer';
|
||||
import { applyArrayPlugins } from './helper/array';
|
||||
|
||||
export { Drawable } from './drawables/drawable';
|
||||
export { DrawableDescriptor } from './drawables/drawable-descriptor';
|
||||
export { CircleLight } from './drawables/lights/circle-light';
|
||||
|
|
@ -13,7 +14,6 @@ export { Circle } from './drawables/shapes/circle';
|
|||
export { InvertedTunnel } from './drawables/shapes/inverted-tunnel';
|
||||
export { Tunnel } from './drawables/shapes/tunnel';
|
||||
export { Renderer } from './graphics/rendering/renderer';
|
||||
export { RenderingPassName } from './graphics/rendering/rendering-pass-name';
|
||||
|
||||
declare global {
|
||||
interface Array<T> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue