diff --git a/README.md b/README.md index c1fab6d..ba2f583 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ A good-looking 2D adventure. - procedural piano - lightweight object storage - docker engine dashboard? +- dockerswarm.rocks - local dev env - prettier script - monitoring - traefik -- digital ocean docker contianer registry +- digital ocean docker container registry - dynamic shader generation diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json index c178efe..20b972e 100644 --- a/frontend/.vscode/settings.json +++ b/frontend/.vscode/settings.json @@ -1,5 +1,8 @@ { "typescript.tsdk": "node_modules\\typescript\\lib", "editor.tabSize": 2, - "editor.formatOnSave": true + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true + } } diff --git a/frontend/src/scripts/drawing/graphics-library/fragment-shader-only-program.ts b/frontend/src/scripts/drawing/graphics-library/fragment-shader-only-program.ts index 1d941c8..56556fa 100644 --- a/frontend/src/scripts/drawing/graphics-library/fragment-shader-only-program.ts +++ b/frontend/src/scripts/drawing/graphics-library/fragment-shader-only-program.ts @@ -1,4 +1,3 @@ -import passthroughVertexShader from '../../../shaders/passthrough-vs.glsl'; import { createShader } from './create-shader'; import { loadUniform } from './load-uniform'; @@ -15,9 +14,10 @@ export class FragmentShaderOnlyProgram { constructor( private gl: WebGL2RenderingContext, + passthroughVertexShaderSource: string, fragmentShaderSource: string ) { - this.createProgram(fragmentShaderSource); + this.createProgram(passthroughVertexShaderSource, fragmentShaderSource); this.prepareScreenQuad('a_position'); this.queryUniforms(); } @@ -74,13 +74,16 @@ export class FragmentShaderOnlyProgram { console.log(this.uniforms); } - private createProgram(fragmentShaderSource: string) { + private createProgram( + passthroughVertexShaderSource: string, + fragmentShaderSource: string + ) { this.program = this.gl.createProgram(); const vertexShader = createShader( this.gl, this.gl.VERTEX_SHADER, - passthroughVertexShader + passthroughVertexShaderSource ); this.gl.attachShader(this.program, vertexShader); this.shaders.push(vertexShader); diff --git a/frontend/src/scripts/drawing/graphics-library/load-uniform.ts b/frontend/src/scripts/drawing/graphics-library/load-uniform.ts index e03167c..8aed086 100644 --- a/frontend/src/scripts/drawing/graphics-library/load-uniform.ts +++ b/frontend/src/scripts/drawing/graphics-library/load-uniform.ts @@ -18,18 +18,27 @@ export const loadUniform = ( > = new Map(); { converters.set(WebGL2RenderingContext.FLOAT, (gl, v, l) => { + if (v.length == 0) { + return; + } gl.uniform1fv(l, new Float32Array(v)); }); converters.set( WebGL2RenderingContext.FLOAT_VEC2, (gl, v: vec2 | Array, l) => { + if (v.length == 0) { + return; + } + if (v[0] instanceof Array) { const result = new Float32Array(v.length * 2); + for (let i = 0; i < v.length; i++) { result[2 * i] = (v[i] as Array).x; result[2 * i + 1] = (v[i] as Array).y; } + gl.uniform2fv(l, new Float32Array(result)); } else { gl.uniform2fv(l, v as vec2); diff --git a/frontend/src/scripts/drawing/webgl2-renderer.ts b/frontend/src/scripts/drawing/webgl2-renderer.ts index 024db43..dba2ccd 100644 --- a/frontend/src/scripts/drawing/webgl2-renderer.ts +++ b/frontend/src/scripts/drawing/webgl2-renderer.ts @@ -1,16 +1,14 @@ -import { Drawer } from './drawer'; -import { mat2d, vec2, mat2, mat3 } from 'gl-matrix'; -import { FragmentShaderOnlyProgram } from './graphics-library/fragment-shader-only-program'; -import { WebGlStopwatch } from './graphics-library/stopwatch'; +import { mat2d, vec2 } from 'gl-matrix'; import { Rectangle } from '../math/rectangle'; -import { IntermediateFrameBuffer } from './graphics-library/intermediate-frame-buffer'; -import { FrameBuffer } from './graphics-library/frame-buffer'; +import { Drawer } from './drawer'; import { DefaultFrameBuffer } from './graphics-library/default-frame-buffer'; -import { translate } from 'gl-matrix/src/gl-matrix/mat2d'; +import { FragmentShaderOnlyProgram } from './graphics-library/fragment-shader-only-program'; +import { IntermediateFrameBuffer } from './graphics-library/intermediate-frame-buffer'; +import { WebGlStopwatch } from './graphics-library/stopwatch'; export class WebGl2Renderer implements Drawer { private gl: WebGL2RenderingContext; - private stopwatch: WebGlStopwatch; + private stopwatch?: WebGlStopwatch; private viewBox: Rectangle = new Rectangle(); private uniforms: any; @@ -21,7 +19,7 @@ export class WebGl2Renderer implements Drawer { constructor( private canvas: HTMLCanvasElement, private overlay: HTMLElement, - shaderSources: Array + shaderSources: Array<[string, string]> ) { this.gl = this.canvas.getContext('webgl2'); if (!this.gl) { @@ -29,14 +27,14 @@ export class WebGl2Renderer implements Drawer { } this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl, [ - new FragmentShaderOnlyProgram(this.gl, shaderSources[0]), + new FragmentShaderOnlyProgram(this.gl, ...shaderSources[0]), ]); this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl, [ - new FragmentShaderOnlyProgram(this.gl, shaderSources[1]), + new FragmentShaderOnlyProgram(this.gl, ...shaderSources[1]), ]); - this.distanceFieldFrameBuffer.renderScale = 0.2; + this.distanceFieldFrameBuffer.renderScale = 1; this.lightingFrameBuffer.renderScale = 1; try { @@ -44,7 +42,7 @@ export class WebGl2Renderer implements Drawer { } catch {} } - startFrame(): void { + public startFrame(): void { this.stopwatch?.start(); this.uniforms = {}; this.distanceFieldFrameBuffer.setSize(); @@ -52,15 +50,31 @@ export class WebGl2Renderer implements Drawer { } public finishFrame() { + this.calculateOwnUniforms(); + + this.distanceFieldFrameBuffer.render(this.uniforms); + this.lightingFrameBuffer.render( + this.uniforms, + this.distanceFieldFrameBuffer.texture + ); + + this.stopwatch?.stop(); + } + + private calculateOwnUniforms() { const resolution = vec2.fromValues(this.canvas.width, this.canvas.height); const distanceScreenToWorld = this.getScreenToWorldTransform( this.distanceFieldFrameBuffer.getSize() ); - const lightingScreenToWorld = this.getScreenToWorldTransform( - this.lightingFrameBuffer.getSize() + const ndcToWorld = mat2d.fromTranslation( + mat2d.create(), + this.viewBox.topLeft ); + mat2d.scale(ndcToWorld, ndcToWorld, this.viewBox.size); + mat2d.scale(ndcToWorld, ndcToWorld, vec2.fromValues(0.5, 0.5)); + mat2d.translate(ndcToWorld, ndcToWorld, vec2.fromValues(1, 1)); const screenToWorld = this.getScreenToWorldTransform(resolution); @@ -79,18 +93,10 @@ export class WebGl2Renderer implements Drawer { this.giveUniforms({ distanceScreenToWorld, - lightingScreenToWorld, worldToDistanceUV, cursorPosition, + ndcToWorld, }); - - this.distanceFieldFrameBuffer.render(this.uniforms); - this.lightingFrameBuffer.render( - this.uniforms, - this.distanceFieldFrameBuffer.texture - ); - - this.stopwatch?.stop(); } private getScreenToWorldTransform(screenSize: vec2) { diff --git a/frontend/src/scripts/game.ts b/frontend/src/scripts/game.ts index 6c68efa..eb885cd 100644 --- a/frontend/src/scripts/game.ts +++ b/frontend/src/scripts/game.ts @@ -1,21 +1,21 @@ +import caveFragmentShader from '../shaders/cave-distance-fs.glsl'; +import lightsShader from '../shaders/lights-shading-fs.glsl'; +import caveVertexShader from '../shaders/passthrough-distance-vs.glsl'; +import lightsVertexShader from '../shaders/passthrough-shading-vs.glsl'; +// import lightsShader from '../shaders/rainbow-shading-fs.glsl'; +import { CommandBroadcaster } from './commands/command-broadcaster'; +import { BeforeDrawCommand } from './commands/types/before-draw'; +import { DrawCommand } from './commands/types/draw'; +import { StepCommand } from './commands/types/step'; import { WebGl2Renderer } from './drawing/webgl2-renderer'; +import { timeIt } from './helper/timing'; import { KeyboardListener } from './input/keyboard-listener'; import { MouseListener } from './input/mouse-listener'; import { TouchListener } from './input/touch-listener'; -import { CommandBroadcaster } from './commands/command-broadcaster'; import { ObjectContainer } from './objects/object-container'; -import { DrawCommand } from './commands/types/draw'; - -import { StepCommand } from './commands/types/step'; import { Character } from './objects/types/character'; -import { InfoText } from './objects/types/info-text'; -import { timeIt } from './helper/timing'; - -import caveFragmentShader from '../shaders/cave-distance-fs.glsl'; -// import lightsShader from '../shaders/rainbow-shading-fs.glsl'; -import lightsShader from '../shaders/lights-shading-fs.glsl'; import { Dungeon } from './objects/types/dungeon'; -import { BeforeDrawCommand } from './commands/types/before-draw'; +import { InfoText } from './objects/types/info-text'; export class Game { private previousTime: DOMHighResTimeStamp = 0; @@ -37,8 +37,8 @@ export class Game { ); this.renderer = new WebGl2Renderer(canvas, overlay, [ - caveFragmentShader, - lightsShader, + [caveVertexShader, caveFragmentShader], + [lightsVertexShader, lightsShader], ]); this.initializeScene(); diff --git a/frontend/src/scripts/objects/game-object.ts b/frontend/src/scripts/objects/game-object.ts index a5a822b..305f86e 100644 --- a/frontend/src/scripts/objects/game-object.ts +++ b/frontend/src/scripts/objects/game-object.ts @@ -1,8 +1,8 @@ -import { Typed } from '../transport/serializable'; -import { IdentityManager } from '../identity/identity-manager'; +import { vec2 } from 'gl-matrix'; import { Command } from '../commands/command'; import { CommandReceiver } from '../commands/command-receiver'; -import { vec2 } from 'gl-matrix'; +import { IdentityManager } from '../identity/identity-manager'; +import { Typed } from '../transport/serializable'; export abstract class GameObject extends Typed implements CommandReceiver { public readonly id = IdentityManager.generateId(); diff --git a/frontend/src/scripts/objects/object-container.ts b/frontend/src/scripts/objects/object-container.ts index 42ef3f1..332c127 100644 --- a/frontend/src/scripts/objects/object-container.ts +++ b/frontend/src/scripts/objects/object-container.ts @@ -1,7 +1,7 @@ -import { GameObject } from './game-object'; -import { Id } from '../identity/identity'; import { Command } from '../commands/command'; import { CommandReceiver } from '../commands/command-receiver'; +import { Id } from '../identity/identity'; +import { GameObject } from './game-object'; export class ObjectContainer implements CommandReceiver { private objects: Map = new Map(); diff --git a/frontend/src/scripts/objects/types/character.ts b/frontend/src/scripts/objects/types/character.ts index 5edb416..84dbf44 100644 --- a/frontend/src/scripts/objects/types/character.ts +++ b/frontend/src/scripts/objects/types/character.ts @@ -1,12 +1,12 @@ +import { vec2 } from 'gl-matrix'; +import { KeyDownCommand } from '../../commands/types/key-down'; +import { KeyUpCommand } from '../../commands/types/key-up'; +import { MoveToCommand } from '../../commands/types/move-to'; +import { StepCommand } from '../../commands/types/step'; +import { SwipeCommand } from '../../commands/types/swipe'; import { GameObject } from '../game-object'; import { ObjectContainer } from '../object-container'; import { Camera } from './camera'; -import { MoveToCommand } from '../../commands/types/move-to'; -import { StepCommand } from '../../commands/types/step'; -import { KeyDownCommand } from '../../commands/types/key-down'; -import { KeyUpCommand } from '../../commands/types/key-up'; -import { SwipeCommand } from '../../commands/types/swipe'; -import { vec2 } from 'gl-matrix'; export class Character extends GameObject { private keysDown: Set = new Set(); diff --git a/frontend/src/scripts/objects/types/dungeon.ts b/frontend/src/scripts/objects/types/dungeon.ts index fcf8784..ff66718 100644 --- a/frontend/src/scripts/objects/types/dungeon.ts +++ b/frontend/src/scripts/objects/types/dungeon.ts @@ -1,6 +1,6 @@ -import { GameObject } from '../game-object'; -import { DrawCommand } from '../../commands/types/draw'; import { vec2 } from 'gl-matrix'; +import { DrawCommand } from '../../commands/types/draw'; +import { GameObject } from '../game-object'; export interface Line { start: vec2; @@ -17,13 +17,13 @@ export class Dungeon extends GameObject { this.addCommandExecutor(DrawCommand, this.draw.bind(this)); - let previousRadius = 0; + let previousRadius = 350; let previousEnd = vec2.create(); for (let i = 0; i < 500000; i += 500) { const height = previousEnd.y + (Math.random() - 0.5) * 2000; const currentEnd = vec2.fromValues(i, height); - const currentToRadius = Math.random() * 10 + 300; + const currentToRadius = Math.random() * 300 + 150; this.lines.push({ start: previousEnd, diff --git a/frontend/src/shaders/cave-distance-fs.glsl b/frontend/src/shaders/cave-distance-fs.glsl index 0fc4db9..8ba4160 100644 --- a/frontend/src/shaders/cave-distance-fs.glsl +++ b/frontend/src/shaders/cave-distance-fs.glsl @@ -36,11 +36,18 @@ float getDistance(in vec2 target) { return -minDistance; } -uniform mat3 distanceScreenToWorld; +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() { - vec2 position = (vec3(gl_FragCoord.xy, 1.0) * distanceScreenToWorld).xy; - float distance = getDistance(position); - fragmentColor = vec4(vec3(0.0), distance / 256.0 + 0.5); + float distance = getDistance(worldCoordinates); + fragmentColor = vec4( + branchlessTernary(distance, vec3(1.0), vec3(0.0, 1.0, 0.5)), + distance / 128.0 + 0.5 + ); } diff --git a/frontend/src/shaders/lights-shading-fs.glsl b/frontend/src/shaders/lights-shading-fs.glsl index 31f68ed..8918c97 100644 --- a/frontend/src/shaders/lights-shading-fs.glsl +++ b/frontend/src/shaders/lights-shading-fs.glsl @@ -3,114 +3,96 @@ precision mediump float; #define INFINITY 10000.0 - -#define LIGHTS_SIZE 3 - -#define LIGHT_PENETRATION 0.95 +#define LIGHT_COUNT 3 +#define LIGHT_PENETRATION 1000.0 #define ANTIALIASING_RADIUS 1.0 +#define AMBIENT_LIGHT vec3(0.075) struct Light { vec2 center; float radius; - vec3 color; - float intensity; + vec3 value; }; uniform sampler2D distanceTexture; uniform mat3 worldToDistanceUV; -uniform mat3 lightingScreenToWorld; uniform vec2 cursorPosition; - -Light lights[LIGHTS_SIZE]; - -float circleDistance(in vec2 position, in Light circle) -{ - return length(position - circle.center) - circle.radius; -} +Light lights[LIGHT_COUNT]; float getDistance(in vec2 target, out vec3 color) { + // should avoid this matrix multiplication vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy; + vec4 values = texture(distanceTexture, targetUV); color = values.rgb; - return (values.a - 0.5) * 256.0; + return (values.a - 0.5) * 128.0; +} + +float getDistance(in vec2 target) { + // should avoid this matrix multiplication + vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy; + + vec4 values = texture(distanceTexture, targetUV); + return (values.a - 0.5) * 128.0; } void createWorld() { - lights[0] = Light(vec2(600, 700), 40.5, vec3(1.0), 25.0); - lights[1] = Light(vec2(100.0, 350.0), 52.5,vec3(2.0, 1.0, 0.25), 20.5); - lights[2] = Light(cursorPosition, 52.5,vec3(0.63, 0.07, 0.19), 200.5); + 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); } -float escapeFromObject(inout vec2 position, in vec2 direction) { - float fractionOfLightPenetrating = 1.0; +float getFractionOfLightArriving( + in vec2 target, + in vec2 direction, + in float lightDistance, + in float lightRadius +) { + float q = INFINITY; float rayLength = 0.0; - for (int i = 0; i < 64; i++) { - vec3 color; - float minDistance = getDistance(position, color); - if (minDistance >= 0.0) { - return fractionOfLightPenetrating; - } - - fractionOfLightPenetrating *= pow(LIGHT_PENETRATION, -minDistance); - rayLength += max(1.0, -minDistance); - position += direction * rayLength; - } - - return 0.0; -} -float getFractionOfLightArriving(in vec2 position, in vec2 direction, in float lightDistance, in float lightRadius) { - float fractionOfLightArriving = 1.0; - vec3 color; - - float rayLength = 0.0; for (int j = 0; j < 64; j++) { - float minDistance = getDistance(position + direction * rayLength, color); - fractionOfLightArriving = min(fractionOfLightArriving, minDistance / rayLength); - rayLength += max(1.0, abs(minDistance)); - - if (rayLength > lightDistance) { - fractionOfLightArriving = (fractionOfLightArriving * lightDistance + lightRadius) / (2.0 * lightRadius); - return smoothstep(0.0, 1.0, fractionOfLightArriving); - } + float minDistance = getDistance(target + direction * rayLength); + q = min(q, minDistance / rayLength); + rayLength = min(lightDistance, rayLength + max(1.0, minDistance)); } - - return 0.0; + return smoothstep(0.0, 1.0, q * (lightDistance + lightRadius) / lightRadius); } -vec3 getPixelColor(in vec2 targetLighting, in bool startsInside, in vec3 colorBias) { +float square(in float a) { + return a*a; +} + +vec3 getPixelColor(in vec2 worldCoordinates) { vec3 result = vec3(0.0); + + vec3 colorAtPosition; + float startingDistance = getDistance(worldCoordinates, colorAtPosition); + float fractionOfLightPenetrating = smoothstep(0.0, 1.0, + 1.0 - (min(0.0, startingDistance) / LIGHT_PENETRATION) + ); - for (int i = 0; i < LIGHTS_SIZE; i++) { + for (int i = 0; i < LIGHT_COUNT; i++) { Light light = lights[i]; - float lightDistance = circleDistance(targetLighting, light); - vec3 lightColor = normalize(light.color) * light.intensity - / mix(1.0, lightDistance, clamp(lightDistance, 0.0, 1.0)); + float lightDistance = distance(worldCoordinates, light.center) - light.radius; + vec3 lightColorAtPosition = light.value / square(max(0.0, lightDistance / 200.0) + 1.0); + vec2 lightDirection = normalize(light.center - worldCoordinates); - if (lightDistance < 0.0) { - return lightColor; - } - - vec2 lightDirection = normalize(light.center - targetLighting); - vec2 rayStart = targetLighting; - - - float fractionOfLightPenetrating = 1.0; - if (startsInside) { - fractionOfLightPenetrating = escapeFromObject(rayStart, lightDirection); - lightColor *= colorBias; - } + float fractionOfLightArriving = getFractionOfLightArriving( + worldCoordinates, lightDirection, max(0.0, lightDistance), light.radius + ); - float fractionOfLightArriving = getFractionOfLightArriving(rayStart, lightDirection, lightDistance, light.radius); - result += lightColor * fractionOfLightArriving * fractionOfLightPenetrating; + result += colorAtPosition * lightColorAtPosition * fractionOfLightArriving * fractionOfLightPenetrating; } + + // 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); @@ -122,21 +104,11 @@ vec3 getPixelColor(in vec2 targetLighting, in bool startsInside, in vec3 colorBi return getPixelColor(position, minDistance < 0.0, minDistance < 0.0 ? nearest.color : vec3(1.0)); }*/ +in vec2 worldCoordinates; out vec4 fragmentColor; - void main() { createWorld(); - - vec2 pixelWorldCoordinates = (vec3(gl_FragCoord.xy, 1.0) * lightingScreenToWorld).xy; - - vec3 color; - float minDistance = getDistance(pixelWorldCoordinates, color); - color = getPixelColor(pixelWorldCoordinates, minDistance < 0.0, minDistance < 0.0 ? color : vec3(1.0)); - - fragmentColor = vec4(color, 1.0); - - if (distance(cursorPosition, pixelWorldCoordinates) < 50.0) { - fragmentColor = vec4(vec3(1.0, 1.0, 0.0), 1.0); - } + // log2 for compenstaion? + fragmentColor = vec4(getPixelColor(worldCoordinates), 1.0); } diff --git a/frontend/src/shaders/passthrough-distance-vs.glsl b/frontend/src/shaders/passthrough-distance-vs.glsl new file mode 100644 index 0000000..e0c033e --- /dev/null +++ b/frontend/src/shaders/passthrough-distance-vs.glsl @@ -0,0 +1,10 @@ +#version 300 es + +uniform mat3 ndcToWorld; +in vec4 a_position; +out vec2 worldCoordinates; + +void main() { + worldCoordinates = (vec3(a_position.xy, 1.0) * ndcToWorld).xy; + gl_Position = a_position; +} diff --git a/frontend/src/shaders/passthrough-shading-vs.glsl b/frontend/src/shaders/passthrough-shading-vs.glsl new file mode 100644 index 0000000..e0c033e --- /dev/null +++ b/frontend/src/shaders/passthrough-shading-vs.glsl @@ -0,0 +1,10 @@ +#version 300 es + +uniform mat3 ndcToWorld; +in vec4 a_position; +out vec2 worldCoordinates; + +void main() { + worldCoordinates = (vec3(a_position.xy, 1.0) * ndcToWorld).xy; + gl_Position = a_position; +} diff --git a/frontend/src/shaders/passthrough-vs.glsl b/frontend/src/shaders/passthrough-vs.glsl deleted file mode 100644 index acfda9a..0000000 --- a/frontend/src/shaders/passthrough-vs.glsl +++ /dev/null @@ -1,7 +0,0 @@ -#version 300 es - -in vec4 a_position; - -void main() { - gl_Position = a_position; -} diff --git a/frontend/src/shaders/rainbow-shading-fs.glsl b/frontend/src/shaders/rainbow-shading-fs.glsl index 91fd598..9c9b0c6 100644 --- a/frontend/src/shaders/rainbow-shading-fs.glsl +++ b/frontend/src/shaders/rainbow-shading-fs.glsl @@ -34,16 +34,17 @@ float getDistance(in vec2 targetUV, out vec3 color) { return values.a; } +in vec2 worldCoordinates; + void main() { - vec2 targetUV = (vec3(gl_FragCoord.xy, 1.0) * worldToDistanceUV).xy; - vec2 targetLighting = (vec3(gl_FragCoord.xy, 1.0) * lightingScreenToWorld).xy; + vec2 targetUV = (vec3(worldCoordinates.xy, 1.0) * worldToDistanceUV).xy; vec4 previous = texture(distanceTexture, targetUV); //fragmentColor = smoothRainbow(previous.a); fragmentColor = previous.a > 0.5 ? vec4(1.0, 1.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 1.0); - if (distance(targetLighting, cursorPosition) < 0.01) { + if (distance(worldCoordinates, cursorPosition) < 10.0) { fragmentColor = vec4(1.0, 1.0, 0.0, 1.0); } }