diff --git a/frontend/src/scripts/drawing/graphics-library/frame-buffer.ts b/frontend/src/scripts/drawing/graphics-library/frame-buffer.ts index a57f6fd..bd449a2 100644 --- a/frontend/src/scripts/drawing/graphics-library/frame-buffer.ts +++ b/frontend/src/scripts/drawing/graphics-library/frame-buffer.ts @@ -1,5 +1,5 @@ -import { FragmentShaderOnlyProgram } from './fragment-shader-only-program'; import { vec2 } from 'gl-matrix'; +import { FragmentShaderOnlyProgram } from './fragment-shader-only-program'; export abstract class FrameBuffer { public renderScale = 1; @@ -13,11 +13,11 @@ export abstract class FrameBuffer { protected programs: Array ) {} - public render(uniforms: any, input?: WebGLTexture) { + public render(uniforms: any, colorInput?: WebGLTexture) { this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer); - if (input !== null) { - this.gl.bindTexture(this.gl.TEXTURE_2D, input); + if (colorInput !== null) { + this.gl.bindTexture(this.gl.TEXTURE_2D, colorInput); } this.gl.viewport(0, 0, this.size.x, this.size.y); diff --git a/frontend/src/scripts/drawing/graphics-library/intermediate-frame-buffer.ts b/frontend/src/scripts/drawing/graphics-library/intermediate-frame-buffer.ts index 2fbf504..0bdc00a 100644 --- a/frontend/src/scripts/drawing/graphics-library/intermediate-frame-buffer.ts +++ b/frontend/src/scripts/drawing/graphics-library/intermediate-frame-buffer.ts @@ -19,7 +19,7 @@ export class IntermediateFrameBuffer extends FrameBuffer { this.setSize(); } - public get texture(): WebGLTexture { + public get colorTexture(): WebGLTexture { return this.frameTexture; } @@ -43,7 +43,11 @@ export class IntermediateFrameBuffer extends FrameBuffer { private configureTexture() { this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); - + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MAG_FILTER, + this.gl.NEAREST + ); this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, diff --git a/frontend/src/scripts/drawing/graphics-library/stopwatch.ts b/frontend/src/scripts/drawing/graphics-library/stopwatch.ts index 93cb365..ba5d08d 100644 --- a/frontend/src/scripts/drawing/graphics-library/stopwatch.ts +++ b/frontend/src/scripts/drawing/graphics-library/stopwatch.ts @@ -1,4 +1,3 @@ -import { WebGl2Renderer } from '../webgl2-renderer'; import { InfoText } from '../../objects/types/info-text'; // https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/ diff --git a/frontend/src/scripts/drawing/webgl2-renderer.ts b/frontend/src/scripts/drawing/webgl2-renderer.ts index dba2ccd..b66236f 100644 --- a/frontend/src/scripts/drawing/webgl2-renderer.ts +++ b/frontend/src/scripts/drawing/webgl2-renderer.ts @@ -34,7 +34,7 @@ export class WebGl2Renderer implements Drawer { new FragmentShaderOnlyProgram(this.gl, ...shaderSources[1]), ]); - this.distanceFieldFrameBuffer.renderScale = 1; + this.distanceFieldFrameBuffer.renderScale = 0.5; this.lightingFrameBuffer.renderScale = 1; try { @@ -55,7 +55,7 @@ export class WebGl2Renderer implements Drawer { this.distanceFieldFrameBuffer.render(this.uniforms); this.lightingFrameBuffer.render( this.uniforms, - this.distanceFieldFrameBuffer.texture + this.distanceFieldFrameBuffer.colorTexture ); this.stopwatch?.stop(); @@ -96,6 +96,7 @@ export class WebGl2Renderer implements Drawer { worldToDistanceUV, cursorPosition, ndcToWorld, + viewBoxSize: this.viewBox.size, }); } diff --git a/frontend/src/shaders/cave-distance-fs.glsl b/frontend/src/shaders/cave-distance-fs.glsl index 8ba4160..002f3e7 100644 --- a/frontend/src/shaders/cave-distance-fs.glsl +++ b/frontend/src/shaders/cave-distance-fs.glsl @@ -1,6 +1,6 @@ #version 300 es -precision mediump float; +precision lowp float; #define INFINITY 10000.0 @@ -19,7 +19,7 @@ float lineDistance( ) { vec2 pa = target - start, ba = end - start; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); - return distance(pa, ba * h) - mix(radiusFrom, radiusTo, smoothstep(0.0, 1.0, h)); + return distance(pa, ba * h) - mix(radiusFrom, radiusTo, h); } float getDistance(in vec2 target) { @@ -36,18 +36,15 @@ float getDistance(in vec2 target) { return -minDistance; } -vec3 branchlessTernary(float condition, vec3 ifPositive, vec3 ifNegative) { - float isPositive = (sign(condition) + 1.0) * 0.5; - return ifPositive * abs(isPositive) + ifNegative * (1.0 - isPositive); -} - in vec2 worldCoordinates; out vec4 fragmentColor; void main() { float distance = getDistance(worldCoordinates); + const vec3 caveColor = vec3(0.0); + const vec3 airColor = vec3(1.0); fragmentColor = vec4( - branchlessTernary(distance, vec3(1.0), vec3(0.0, 1.0, 0.5)), - distance / 128.0 + 0.5 + mix(caveColor, airColor, distance), + distance / 32.0 ); } diff --git a/frontend/src/shaders/lights-shading-fs.glsl b/frontend/src/shaders/lights-shading-fs.glsl index 8918c97..a59ccb9 100644 --- a/frontend/src/shaders/lights-shading-fs.glsl +++ b/frontend/src/shaders/lights-shading-fs.glsl @@ -4,21 +4,24 @@ precision mediump float; #define INFINITY 10000.0 #define LIGHT_COUNT 3 -#define LIGHT_PENETRATION 1000.0 -#define ANTIALIASING_RADIUS 1.0 -#define AMBIENT_LIGHT vec3(0.075) +#define AMBIENT_LIGHT vec3(0.05) +#define LIGHT_DROP 800.0 +#define SHADOW_BIAS 0.01 struct Light { vec2 center; float radius; vec3 value; -}; +}[LIGHT_COUNT] lights; uniform sampler2D distanceTexture; uniform mat3 worldToDistanceUV; uniform vec2 cursorPosition; +uniform vec2 viewBoxSize; -Light lights[LIGHT_COUNT]; +float square(in float a) { + return a*a; +} float getDistance(in vec2 target, out vec3 color) { // should avoid this matrix multiplication @@ -26,7 +29,7 @@ float getDistance(in vec2 target, out vec3 color) { vec4 values = texture(distanceTexture, targetUV); color = values.rgb; - return (values.a - 0.5) * 128.0; + return values.w * 32.0; } float getDistance(in vec2 target) { @@ -34,81 +37,67 @@ float getDistance(in vec2 target) { vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy; vec4 values = texture(distanceTexture, targetUV); - return (values.a - 0.5) * 128.0; + return values.w * 32.0; } void createWorld() { - lights[0] = Light(vec2(600, 700), 40.5, normalize(vec3(1.0)) * 2.0); - lights[1] = Light(vec2(100.0, 350.0), 52.5, normalize(vec3(2.0, 1.0, 0.25)) * 0.5); - lights[2] = Light(cursorPosition, 52.5, normalize(vec3(0.63, 0.25, 0.5)) * 1.0); + //lights[0] = Light(vec2(600, 700), 40.5, normalize(vec3(1.0)) * 2.0); + //lights[1] = Light(vec2(100.0, 350.0), 52.5, normalize(vec3(2.0, 1.0, 0.25)) * 0.5); + lights[2] = Light(cursorPosition, 52.5, normalize(vec3(0.93, 0.25, 0.5)) * 1.0); } float getFractionOfLightArriving( in vec2 target, in vec2 direction, + in float startingDistance, in float lightDistance, in float lightRadius ) { float q = INFINITY; float rayLength = 0.0; + float movingAverageMeanDistance = startingDistance; + for (int j = 0; j < 64; j++) { float minDistance = getDistance(target + direction * rayLength); - q = min(q, minDistance / rayLength); - rayLength = min(lightDistance, rayLength + max(1.0, minDistance)); + movingAverageMeanDistance = movingAverageMeanDistance / 2.0 + minDistance / 2.0; + q = min(q, movingAverageMeanDistance / rayLength); + rayLength = min(lightDistance, rayLength + max(0.0001, minDistance)); } - return smoothstep(0.0, 1.0, q * (lightDistance + lightRadius) / lightRadius); + return smoothstep(0.0, 1.0, (q - SHADOW_BIAS) * (lightDistance + lightRadius) / lightRadius); } -float square(in float a) { - return a*a; -} - -vec3 getPixelColor(in vec2 worldCoordinates) { - vec3 result = vec3(0.0); - +vec3 getPixelColor(in vec2 worldCoordinates, in vec2 uvCoordinates) { vec3 colorAtPosition; float startingDistance = getDistance(worldCoordinates, colorAtPosition); - float fractionOfLightPenetrating = smoothstep(0.0, 1.0, - 1.0 - (min(0.0, startingDistance) / LIGHT_PENETRATION) - ); + + vec3 result = colorAtPosition * AMBIENT_LIGHT; for (int i = 0; i < LIGHT_COUNT; i++) { Light light = lights[i]; float lightDistance = distance(worldCoordinates, light.center) - light.radius; - vec3 lightColorAtPosition = light.value / square(max(0.0, lightDistance / 200.0) + 1.0); + vec3 lightColorAtPosition = light.value / square(max(0.0, lightDistance / LIGHT_DROP) + 1.0); vec2 lightDirection = normalize(light.center - worldCoordinates); float fractionOfLightArriving = getFractionOfLightArriving( - worldCoordinates, lightDirection, max(0.0, lightDistance), light.radius + worldCoordinates, lightDirection, startingDistance, + max(0.0, lightDistance), light.radius ); - result += colorAtPosition * lightColorAtPosition * fractionOfLightArriving * fractionOfLightPenetrating; + result += colorAtPosition * lightColorAtPosition * fractionOfLightArriving; } - - // Add ambient light - result += colorAtPosition * AMBIENT_LIGHT; return clamp(result, 0.0, 1.0); } -/*vec3 getPixelColorAntialiased(in vec2 position) { - Circle nearest; - float minDistance = getDistance(position, nearest); - if (0.0 < minDistance && minDistance < 1.0) { - vec2 closerDirection = normalize(nearest.center - position); - return mix(getPixelColor(position + closerDirection, true, nearest.color), getPixelColor(position - closerDirection, false, nearest.color), minDistance); - } - - return getPixelColor(position, minDistance < 0.0, minDistance < 0.0 ? nearest.color : vec3(1.0)); -}*/ in vec2 worldCoordinates; +in vec2 uvCoordinates; out vec4 fragmentColor; void main() { createWorld(); - // log2 for compenstaion? - fragmentColor = vec4(getPixelColor(worldCoordinates), 1.0); + + fragmentColor = vec4(getPixelColor(worldCoordinates, uvCoordinates), 1.0); } diff --git a/frontend/src/shaders/passthrough-shading-vs.glsl b/frontend/src/shaders/passthrough-shading-vs.glsl index e0c033e..80e9724 100644 --- a/frontend/src/shaders/passthrough-shading-vs.glsl +++ b/frontend/src/shaders/passthrough-shading-vs.glsl @@ -3,8 +3,10 @@ uniform mat3 ndcToWorld; in vec4 a_position; out vec2 worldCoordinates; +out vec2 uvCoordinates; void main() { worldCoordinates = (vec3(a_position.xy, 1.0) * ndcToWorld).xy; + uvCoordinates = ((a_position.xy + vec2(1.0)) / 2.0).xy; gl_Position = a_position; }