From 98d1fc9ca2d555013611741995be3e3221abcd0f Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Wed, 23 Sep 2020 16:27:02 +0200 Subject: [PATCH] Add palette system --- src/drawables/shapes/circle.ts | 2 +- src/drawables/shapes/tunnel.ts | 2 +- .../frame-buffer/frame-buffer.ts | 11 ++- .../frame-buffer/intermediate-frame-buffer.ts | 26 ++++-- .../graphics-library/helper/load-uniform.ts | 4 + .../graphics-library/helper/stopwatch.ts | 2 +- .../graphics-library/palette-texture.ts | 66 +++++++++++++ .../graphics-library/parallel-compiler.ts | 22 +++-- .../graphics-library/program/program.ts | 2 +- .../uniform-array-autoscaling-program.ts | 4 +- .../render-pass/distance-render-pass.ts | 4 +- .../render-pass/lights-render-pass.ts | 4 +- .../rendering/renderer-implementation.ts | 93 +++++++++++-------- .../rendering/settings/runtime-settings.ts | 1 + .../rendering/settings/startup-settings.ts | 3 +- .../rendering/shaders/shading-fs-100.glsl | 10 +- .../rendering/shaders/shading-fs.glsl | 7 +- src/graphics/rendering/uniforms-provider.ts | 42 ++++----- src/main.ts | 4 +- 19 files changed, 196 insertions(+), 113 deletions(-) create mode 100644 src/graphics/graphics-library/palette-texture.ts diff --git a/src/drawables/shapes/circle.ts b/src/drawables/shapes/circle.ts index 9d27426..d3e945d 100644 --- a/src/drawables/shapes/circle.ts +++ b/src/drawables/shapes/circle.ts @@ -16,7 +16,7 @@ export class Circle extends Drawable { myMinDistance = min(myMinDistance, dist); } minDistance = min(minDistance, myMinDistance); - color = mix(2.0, color, step( + color = mix(1.0 / {paletteSize}, color, step( distanceNdcPixelSize + SURFACE_OFFSET, myMinDistance )); diff --git a/src/drawables/shapes/tunnel.ts b/src/drawables/shapes/tunnel.ts index 4f77758..ee2f435 100644 --- a/src/drawables/shapes/tunnel.ts +++ b/src/drawables/shapes/tunnel.ts @@ -33,7 +33,7 @@ export class Tunnel extends Drawable { myMinDistance = min(myMinDistance, currentDistance); } - color = mix(2.0, color, step( + color = mix(2.0 / {paletteSize}, color, step( distanceNdcPixelSize + SURFACE_OFFSET, myMinDistance )); diff --git a/src/graphics/graphics-library/frame-buffer/frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/frame-buffer.ts index 540cf88..eeafb13 100644 --- a/src/graphics/graphics-library/frame-buffer/frame-buffer.ts +++ b/src/graphics/graphics-library/frame-buffer/frame-buffer.ts @@ -10,14 +10,15 @@ export abstract class FrameBuffer { // null means the default framebuffer protected frameBuffer: WebGLFramebuffer | null = null; - constructor(protected gl: UniversalRenderingContext) {} + constructor(protected readonly gl: UniversalRenderingContext) {} - public bindAndClear(colorInput?: WebGLTexture) { + public bindAndClear(inputTextures: Array) { this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer); - if (colorInput) { - this.gl.bindTexture(this.gl.TEXTURE_2D, colorInput); - } + inputTextures.forEach((t, i) => { + this.gl.activeTexture(this.gl.TEXTURE0 + i); + this.gl.bindTexture(this.gl.TEXTURE_2D, t); + }); this.gl.viewport(0, 0, this.size.x, this.size.y); this.gl.clearColor(0, 0, 0, 0); diff --git a/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts index 40e2d41..c56cc1b 100644 --- a/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts +++ b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts @@ -4,16 +4,16 @@ import { FrameBuffer } from './frame-buffer'; export class IntermediateFrameBuffer extends FrameBuffer { private frameTexture: WebGLTexture; + private floatEnabled = false; private floatLinearEnabled = false; constructor(gl: UniversalRenderingContext) { super(gl); - if (gl.isWebGL2) { - enableExtension(gl, 'EXT_color_buffer_float'); - } - try { + enableExtension(gl, 'EXT_color_buffer_float'); + this.floatEnabled = true; + enableExtension(gl, 'OES_texture_float_linear'); this.floatLinearEnabled = true; } catch { @@ -21,6 +21,8 @@ export class IntermediateFrameBuffer extends FrameBuffer { } // can only return null on lost context + gl.activeTexture(gl.TEXTURE0); + this.frameTexture = this.gl.createTexture()!; this.configureTexture(); @@ -43,17 +45,17 @@ export class IntermediateFrameBuffer extends FrameBuffer { const hasChanged = super.setSize(); if (hasChanged) { - this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); + this.bind(); this.gl.texImage2D( this.gl.TEXTURE_2D, 0, - this.gl.isWebGL2 ? this.gl.RG16F : this.gl.RGBA, + this.floatEnabled ? this.gl.RG16F : this.gl.RGB, this.size.x, this.size.y, 0, - this.gl.isWebGL2 ? this.gl.RG : this.gl.RGBA, - this.gl.isWebGL2 ? this.gl.FLOAT : this.gl.UNSIGNED_BYTE, + this.floatEnabled ? this.gl.RG : this.gl.RGB, + this.floatEnabled ? this.gl.FLOAT : this.gl.UNSIGNED_BYTE, null ); } @@ -61,8 +63,14 @@ export class IntermediateFrameBuffer extends FrameBuffer { return hasChanged; } - private configureTexture() { + private bind() { + this.gl.activeTexture(this.gl.TEXTURE0); this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); + } + + private configureTexture() { + this.bind(); + this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, diff --git a/src/graphics/graphics-library/helper/load-uniform.ts b/src/graphics/graphics-library/helper/load-uniform.ts index f6622e1..fa29eb1 100644 --- a/src/graphics/graphics-library/helper/load-uniform.ts +++ b/src/graphics/graphics-library/helper/load-uniform.ts @@ -14,6 +14,10 @@ export const loadUniform = ( (gl: UniversalRenderingContext, value: any, location: WebGLUniformLocation) => void > = new Map(); { + converters.set(WebGLRenderingContext.SAMPLER_2D, (gl, v, l) => { + gl.uniform1i(l, v); + }); + converters.set(WebGLRenderingContext.FLOAT, (gl, v, l) => { if (v instanceof Array || v[0] instanceof Float32Array) { if (v.length == 0) { diff --git a/src/graphics/graphics-library/helper/stopwatch.ts b/src/graphics/graphics-library/helper/stopwatch.ts index 55a15de..01a4c09 100644 --- a/src/graphics/graphics-library/helper/stopwatch.ts +++ b/src/graphics/graphics-library/helper/stopwatch.ts @@ -14,7 +14,7 @@ export class WebGlStopwatch { private timerExtension: any; private timerQuery?: WebGLQuery; - constructor(private gl: UniversalRenderingContext) { + constructor(private readonly gl: UniversalRenderingContext) { this.timerExtension = enableExtension(gl, 'EXT_disjoint_timer_query_webgl2'); } diff --git a/src/graphics/graphics-library/palette-texture.ts b/src/graphics/graphics-library/palette-texture.ts new file mode 100644 index 0000000..23eec21 --- /dev/null +++ b/src/graphics/graphics-library/palette-texture.ts @@ -0,0 +1,66 @@ +import { vec3, vec4 } from 'gl-matrix'; +import { UniversalRenderingContext } from './universal-rendering-context'; + +export class PaletteTexture { + private texture: WebGLTexture; + + constructor( + private readonly gl: UniversalRenderingContext, + private readonly paletteSize: number + ) { + this.texture = gl.createTexture()!; + this.bind(); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + } + + public get colorTexture(): WebGLTexture { + return this.texture; + } + + private bind() { + this.gl.activeTexture(this.gl.TEXTURE1); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); + } + + public setPalette(colors: Array) { + const canvas = document.createElement('canvas'); + canvas.width = this.paletteSize; + canvas.height = 1; + + const ctx = canvas.getContext('2d')!; + const imageData = ctx.createImageData(this.paletteSize, 1); + + colors.forEach((c, i) => { + imageData.data[4 * i + 0] = c[0] * 255; + imageData.data[4 * i + 1] = c[1] * 255; + imageData.data[4 * i + 2] = c[2] * 255; + imageData.data[4 * i + 3] = c.length == 4 ? c[3] : 255; + }); + ctx.putImageData(imageData, 0, 0); + + document.body.appendChild(canvas); + + this.setImage(canvas); + } + + public setImage(image: TexImageSource) { + this.bind(); + + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RGBA, + this.gl.RGBA, + this.gl.UNSIGNED_BYTE, + image + ); + } + + public destroy() { + this.gl.deleteTexture(this.texture); + } +} diff --git a/src/graphics/graphics-library/parallel-compiler.ts b/src/graphics/graphics-library/parallel-compiler.ts index 8449594..cb7df2e 100644 --- a/src/graphics/graphics-library/parallel-compiler.ts +++ b/src/graphics/graphics-library/parallel-compiler.ts @@ -75,10 +75,16 @@ export abstract class ParallelCompiler { program: WebGLProgram, substitutions: { [name: string]: string } ): ShaderWithSource { - const processedSource = source.replace(/{(.+)}/gm, (_, name: string): string => { - const value = substitutions[name]; - return Number.isInteger(value) ? `${value}.0` : value; - }); + let processedSource = source; + let replaceHappened: boolean; + do { + replaceHappened = false; + processedSource = processedSource.replace(/{(.+)}/gm, (_, name: string): string => { + replaceHappened = true; + const value = substitutions[name]; + return Number.isInteger(value) ? `${value}.0` : value; + }); + } while (replaceHappened); // can only return null on lost context const shader = ParallelCompiler.gl.createShader(type)!; @@ -136,11 +142,9 @@ export abstract class ParallelCompiler { try { ParallelCompiler.checkShader(shader); } catch (e) { - for (const match of e - .toString() - .matchAll(/ERROR: 0:(?\d+): (?.*)$/gm)) { - const line = Number.parseInt(match.groups.line); - const error = match.groups.error; + for (const match of e.toString().matchAll(/ERROR: 0:(\d+): (.*)$/gm)) { + const line = Number.parseInt(match[1]); + const error = match[2]; console.error( `Error: ${error}\nSource (line ${line}):\n${ shader.source.split('\n')[line - 1] diff --git a/src/graphics/graphics-library/program/program.ts b/src/graphics/graphics-library/program/program.ts index b8b3205..04651a4 100644 --- a/src/graphics/graphics-library/program/program.ts +++ b/src/graphics/graphics-library/program/program.ts @@ -15,7 +15,7 @@ export default abstract class Program implements IProgram { type: GLenum; }> = []; - constructor(protected gl: UniversalRenderingContext) {} + constructor(protected readonly gl: UniversalRenderingContext) {} public async initialize( [vertexShaderSource, fragmentShaderSource]: [string, string], diff --git a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts index d51544a..3e67f40 100644 --- a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts +++ b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts @@ -17,7 +17,7 @@ export class UniformArrayAutoScalingProgram implements IProgram { private drawingRectangleBottomLeft = vec2.fromValues(0, 0); private drawingRectangleSize = vec2.fromValues(1, 1); - constructor(private gl: UniversalRenderingContext) {} + constructor(private readonly gl: UniversalRenderingContext) {} public async initialize( shaderSources: [string, string], @@ -86,10 +86,10 @@ export class UniformArrayAutoScalingProgram implements IProgram { shaderSources: [string, string] ): Promise { const processedSubstitutions = { - ...substitutions, macroDefinitions: this.getMacroDefinitions(combination, descriptors), declarations: this.getDeclarations(combination, descriptors), functionCalls: this.getFunctionCalls(combination, descriptors), + ...substitutions, }; const program = new FragmentShaderOnlyProgram(this.gl); diff --git a/src/graphics/rendering/render-pass/distance-render-pass.ts b/src/graphics/rendering/render-pass/distance-render-pass.ts index b48cf03..646ff0b 100644 --- a/src/graphics/rendering/render-pass/distance-render-pass.ts +++ b/src/graphics/rendering/render-pass/distance-render-pass.ts @@ -13,8 +13,8 @@ export class DistanceRenderPass extends RenderPass { this.drawables.push(drawable); } - public render(commonUniforms: any, inputTexture?: WebGLTexture) { - this.frame.bindAndClear(inputTexture); + public render(commonUniforms: any, ...inputTextures: Array) { + this.frame.bindAndClear(inputTextures); const stepsInUV = 1 / this.tileMultiplier; diff --git a/src/graphics/rendering/render-pass/lights-render-pass.ts b/src/graphics/rendering/render-pass/lights-render-pass.ts index baec1a9..e64a0a3 100644 --- a/src/graphics/rendering/render-pass/lights-render-pass.ts +++ b/src/graphics/rendering/render-pass/lights-render-pass.ts @@ -12,8 +12,8 @@ export class LightsRenderPass extends RenderPass { this.drawables.push(drawable); } - public render(commonUniforms: any, inputTexture?: WebGLTexture) { - this.frame.bindAndClear(inputTexture); + public render(commonUniforms: any, ...inputTextures: Array) { + this.frame.bindAndClear(inputTextures); const tileCenterWorldCoordinates = vec2.transformMat2d( vec2.create(), diff --git a/src/graphics/rendering/renderer-implementation.ts b/src/graphics/rendering/renderer-implementation.ts index e9989b5..acb3c1f 100644 --- a/src/graphics/rendering/renderer-implementation.ts +++ b/src/graphics/rendering/renderer-implementation.ts @@ -1,4 +1,4 @@ -import { vec2, vec3 } from 'gl-matrix'; +import { vec2 } from 'gl-matrix'; import { Drawable } from '../../drawables/drawable'; import { DrawableDescriptor } from '../../drawables/drawable-descriptor'; import { LightDrawable } from '../../drawables/lights/light-drawable'; @@ -6,6 +6,7 @@ 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'; import { WebGlStopwatch } from '../graphics-library/helper/stopwatch'; +import { PaletteTexture } from '../graphics-library/palette-texture'; import { ParallelCompiler } from '../graphics-library/parallel-compiler'; import { getUniversalRenderingContext, @@ -29,13 +30,14 @@ import lightsVertexShader from './shaders/shading-vs.glsl'; import { UniformsProvider } from './uniforms-provider'; export class RendererImplementation implements Renderer { - private gl: UniversalRenderingContext; + private readonly gl: UniversalRenderingContext; private stopwatch?: WebGlStopwatch; private uniformsProvider: UniformsProvider; private distanceFieldFrameBuffer: IntermediateFrameBuffer; private distancePass: DistanceRenderPass; - private lightsPass: LightsRenderPass; private lightingFrameBuffer: DefaultFrameBuffer; + private lightsPass: LightsRenderPass; + private palette?: PaletteTexture; private autoscaler: FpsAutoscaler; private applyRuntimeSettings: { @@ -45,25 +47,17 @@ export class RendererImplementation implements Renderer { this.distanceFieldFrameBuffer.enableHighDpiRendering = v; this.lightingFrameBuffer.enableHighDpiRendering = v; }, - tileMultiplier: (v) => { - this.distancePass.tileMultiplier = v; - }, - isWorldInverted: (v) => { - this.distancePass.isWorldInverted = v; - }, - shadowLength: (v) => { - this.uniformsProvider.shadowLength = v; - }, - ambientLight: (v) => { - this.uniformsProvider.ambientLight = v; - }, - lightCutoffDistance: (v) => { - this.lightsPass.lightCutoffDistance = v; - }, + tileMultiplier: (v) => (this.distancePass.tileMultiplier = v), + isWorldInverted: (v) => (this.distancePass.isWorldInverted = v), + shadowLength: (v) => (this.uniformsProvider.shadowLength = v), + ambientLight: (v) => (this.uniformsProvider.ambientLight = v), + lightCutoffDistance: (v) => (this.lightsPass.lightCutoffDistance = v), + colorPalette: (v) => this.palette!.setPalette(v), }; private static defaultStartupSettings: StartupSettings = { - shadowTraceCount: '16', + shadowTraceCount: 16, + paletteSize: 4, }; setRuntimeSettings(overrides: Partial): void { @@ -88,6 +82,8 @@ export class RendererImplementation implements Renderer { this.uniformsProvider = new UniformsProvider(this.gl); + this.queryPrecisions(); + this.autoscaler = new FpsAutoscaler({ distanceRenderScale: (v) => (this.distanceFieldFrameBuffer.renderScale = v as number), @@ -95,15 +91,13 @@ export class RendererImplementation implements Renderer { }); } - public async initialize( - palette: Array, - settingsOverrides: Partial - ): Promise { + public async initialize(settingsOverrides: Partial): Promise { const settings = { ...RendererImplementation.defaultStartupSettings, ...settingsOverrides, }; + this.palette = new PaletteTexture(this.gl, settings.paletteSize); const promises: Array> = []; promises.push( @@ -111,7 +105,10 @@ export class RendererImplementation implements Renderer { this.gl.isWebGL2 ? [distanceVertexShader, distanceFragmentShader] : [distanceVertexShader100, distanceFragmentShader100], - this.descriptors.filter(RendererImplementation.hasSdf) + this.descriptors.filter(RendererImplementation.hasSdf), + { + paletteSize: settings.paletteSize, + } ) ); promises.push( @@ -121,9 +118,7 @@ export class RendererImplementation implements Renderer { : [lightsVertexShader100, lightsFragmentShader100], this.descriptors.filter((d) => !RendererImplementation.hasSdf(d)), { - palette: this.generatePaletteCode(palette), - colorCount: palette.length.toString(), - shadowTraceCount: settings.shadowTraceCount, + shadowTraceCount: settings.shadowTraceCount.toString(), } ) ); @@ -147,6 +142,30 @@ export class RendererImplementation implements Renderer { return Object.prototype.hasOwnProperty.call(descriptor, 'sdf'); } + private queryPrecisions() { + const precisionToObject = (shader: GLenum, precision: GLenum) => { + const toExponent = (v: number): string => `2^${v}`; + const p = this.gl.getShaderPrecisionFormat(shader, precision)!; + return { + range: `[${toExponent(p.rangeMin)}, ${toExponent(p.rangeMax)}]`, + precision: toExponent(p.precision), + }; + }; + + Insights.setValue('precisions', { + 'vertex shader': { + 'low float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.LOW_FLOAT), + 'medium float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.MEDIUM_FLOAT), + 'high float': precisionToObject(this.gl.VERTEX_SHADER, this.gl.HIGH_FLOAT), + }, + 'fragment shader': { + 'low float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.LOW_FLOAT), + 'medium float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.MEDIUM_FLOAT), + 'high float': precisionToObject(this.gl.FRAGMENT_SHADER, this.gl.HIGH_FLOAT), + }, + }); + } + public addDrawable(drawable: Drawable): void { if ( RendererImplementation.hasSdf((drawable.constructor as typeof Drawable).descriptor) @@ -161,18 +180,6 @@ export class RendererImplementation implements Renderer { this.autoscaler.autoscale(deltaTime); } - private generatePaletteCode(palette: Array) { - const numberToGlslFloat = (n: number) => (Number.isInteger(n) ? `${n}.0` : `${n}`); - return palette - .map( - (c, i) => - `${this.gl.isWebGL2 ? '' : `colors[${i}] = `}vec3(${numberToGlslFloat( - c[0] - )}, ${numberToGlslFloat(c[1])}, ${numberToGlslFloat(c[2])})` - ) - .join(this.gl.isWebGL2 ? ',\n' : ';\n'); - } - public renderDrawables() { if (this.stopwatch) { if (this.stopwatch.isReady) { @@ -190,6 +197,10 @@ export class RendererImplementation implements Renderer { this.lightingFrameBuffer.setSize(); const common = { + // texture units + distanceTexture: 0, + palette: 1, + // regular uniforms distanceNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()), shadingNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()), }; @@ -197,7 +208,8 @@ export class RendererImplementation implements Renderer { this.distancePass.render(this.uniformsProvider.getUniforms(common)); this.lightsPass.render( this.uniformsProvider.getUniforms(common), - this.distanceFieldFrameBuffer.colorTexture + this.distanceFieldFrameBuffer.colorTexture, + this.palette!.colorTexture ); if (this.stopwatch?.isRunning) { @@ -220,5 +232,6 @@ export class RendererImplementation implements Renderer { public destroy(): void { this.distancePass.destroy(); this.lightsPass.destroy(); + this.palette!.destroy(); } } diff --git a/src/graphics/rendering/settings/runtime-settings.ts b/src/graphics/rendering/settings/runtime-settings.ts index 88d39b9..68d1dfc 100644 --- a/src/graphics/rendering/settings/runtime-settings.ts +++ b/src/graphics/rendering/settings/runtime-settings.ts @@ -6,5 +6,6 @@ export interface RuntimeSettings { isWorldInverted: boolean; shadowLength: number; lightCutoffDistance: number; + colorPalette: Array; ambientLight: vec3; } diff --git a/src/graphics/rendering/settings/startup-settings.ts b/src/graphics/rendering/settings/startup-settings.ts index 9c7e11a..03cd6ce 100644 --- a/src/graphics/rendering/settings/startup-settings.ts +++ b/src/graphics/rendering/settings/startup-settings.ts @@ -1,3 +1,4 @@ export interface StartupSettings { - shadowTraceCount: string; + shadowTraceCount: number; + paletteSize: number; } diff --git a/src/graphics/rendering/shaders/shading-fs-100.glsl b/src/graphics/rendering/shaders/shading-fs-100.glsl index 2aca79e..4552c0b 100644 --- a/src/graphics/rendering/shaders/shading-fs-100.glsl +++ b/src/graphics/rendering/shaders/shading-fs-100.glsl @@ -12,16 +12,16 @@ uniform vec2 squareToAspectRatioTimes2; uniform float shadingNdcPixelSize; uniform float shadowLength; uniform sampler2D distanceTexture; +uniform sampler2D palette; varying vec2 position; varying vec2 uvCoordinates; -uniform vec3 ambientLight; -vec3 colors[{colorCount}]; +uniform vec3 ambientLight; float getDistance(in vec2 target, out vec3 color) { vec4 values = texture2D(distanceTexture, target); - color = vec3(0.5); + color = texture2D(palette, vec2(values[1], 0.0)).rgb; return values[0]; } @@ -72,13 +72,11 @@ float shadowTransparency(float startingDistance, float lightCenterDistance, vec2 void main() { vec3 lighting = ambientLight; - - {palette}; vec3 colorAtPosition; float startingDistance = getDistance(uvCoordinates, colorAtPosition); - if (startingDistance < 0.0) { + if (startingDistance <= 0.0) { #ifdef CIRCLE_LIGHT_COUNT #if CIRCLE_LIGHT_COUNT > 0 for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) { diff --git a/src/graphics/rendering/shaders/shading-fs.glsl b/src/graphics/rendering/shaders/shading-fs.glsl index f54aa70..b90185a 100644 --- a/src/graphics/rendering/shaders/shading-fs.glsl +++ b/src/graphics/rendering/shaders/shading-fs.glsl @@ -12,19 +12,16 @@ uniform vec2 squareToAspectRatioTimes2; uniform float shadingNdcPixelSize; uniform float shadowLength; uniform sampler2D distanceTexture; +uniform sampler2D palette; in vec2 position; in vec2 uvCoordinates; uniform vec3 ambientLight; -vec3[{colorCount}] colors = vec3[]( - {palette} -); - float getDistance(in vec2 target, out vec3 color) { vec4 values = texture(distanceTexture, target); - color = colors[int(values[1])]; + color = texture(palette, vec2(values[1], 0.0)).rgb; return values[0]; } diff --git a/src/graphics/rendering/uniforms-provider.ts b/src/graphics/rendering/uniforms-provider.ts index 6ec7c88..636ba03 100644 --- a/src/graphics/rendering/uniforms-provider.ts +++ b/src/graphics/rendering/uniforms-provider.ts @@ -7,13 +7,12 @@ export class UniformsProvider { private scaleWorldLengthToNDC = 1; private transformWorldToNDC = mat2d.create(); - private viewAreaBottomLeft = vec2.create(); private worldAreaInView = vec2.create(); private squareToAspectRatio = vec2.create(); private uvToWorld = mat2d.create(); - public constructor(private gl: UniversalRenderingContext) {} + public constructor(private readonly gl: UniversalRenderingContext) {} public getUniforms(uniforms: any): any { return { @@ -23,34 +22,12 @@ export class UniformsProvider { uvToWorld: this.uvToWorld, worldAreaInView: this.worldAreaInView, squareToAspectRatio: this.squareToAspectRatio, + squareToAspectRatioTimes2: vec2.scale(vec2.create(), this.squareToAspectRatio, 2), scaleWorldLengthToNDC: this.scaleWorldLengthToNDC, transformWorldToNDC: this.transformWorldToNDC, - squareToAspectRatioTimes2: vec2.scale(vec2.create(), this.squareToAspectRatio, 2), }; } - private getScreenToWorldTransform(screenSize: vec2) { - const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); - mat2d.scale( - transform, - transform, - vec2.divide(vec2.create(), this.worldAreaInView, screenSize) - ); - mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5)); - - return transform; - } - - public uvToWorldCoordinate(screenUvPosition: vec2): vec2 { - const resolution = vec2.fromValues(this.gl.canvas.width, this.gl.canvas.height); - - return vec2.transformMat2d( - vec2.create(), - vec2.multiply(vec2.create(), screenUvPosition, resolution), - this.getScreenToWorldTransform(resolution) - ); - } - public getViewArea(): vec2 { return this.worldAreaInView; } @@ -91,4 +68,19 @@ export class UniformsProvider { this.uvToWorld = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); mat2d.scale(this.uvToWorld, this.uvToWorld, this.worldAreaInView); } + + public screenToWorldPosition(screenPosition: vec2): vec2 { + const resolution = vec2.fromValues(this.gl.canvas.width, this.gl.canvas.height); + + const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); + + mat2d.scale( + transform, + transform, + vec2.divide(vec2.create(), this.worldAreaInView, resolution) + ); + mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5)); + + return vec2.transformMat2d(vec2.create(), screenPosition, transform); + } } diff --git a/src/main.ts b/src/main.ts index c55acfc..1f5445b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,3 @@ -import { vec3 } from 'gl-matrix'; import { DrawableDescriptor } from './drawables/drawable-descriptor'; import { Insights } from './graphics/rendering/insights'; import { Renderer } from './graphics/rendering/renderer'; @@ -32,12 +31,11 @@ applyArrayPlugins(); export async function compile( canvas: HTMLCanvasElement, descriptors: Array, - palette: Array, settings: Partial = {} ): Promise { return Insights.measureFunction('startup', async () => { const renderer = new RendererImplementation(canvas, descriptors); - await renderer.initialize(palette, settings); + await renderer.initialize(settings); return renderer; }); }