Try to fix the lighting
This commit is contained in:
parent
affb1b4f4f
commit
e6782a9a98
7 changed files with 51 additions and 59 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { FragmentShaderOnlyProgram } from './fragment-shader-only-program';
|
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
|
import { FragmentShaderOnlyProgram } from './fragment-shader-only-program';
|
||||||
|
|
||||||
export abstract class FrameBuffer {
|
export abstract class FrameBuffer {
|
||||||
public renderScale = 1;
|
public renderScale = 1;
|
||||||
|
|
@ -13,11 +13,11 @@ export abstract class FrameBuffer {
|
||||||
protected programs: Array<FragmentShaderOnlyProgram>
|
protected programs: Array<FragmentShaderOnlyProgram>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public render(uniforms: any, input?: WebGLTexture) {
|
public render(uniforms: any, colorInput?: WebGLTexture) {
|
||||||
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer);
|
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer);
|
||||||
|
|
||||||
if (input !== null) {
|
if (colorInput !== null) {
|
||||||
this.gl.bindTexture(this.gl.TEXTURE_2D, input);
|
this.gl.bindTexture(this.gl.TEXTURE_2D, colorInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gl.viewport(0, 0, this.size.x, this.size.y);
|
this.gl.viewport(0, 0, this.size.x, this.size.y);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export class IntermediateFrameBuffer extends FrameBuffer {
|
||||||
this.setSize();
|
this.setSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get texture(): WebGLTexture {
|
public get colorTexture(): WebGLTexture {
|
||||||
return this.frameTexture;
|
return this.frameTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +43,11 @@ export class IntermediateFrameBuffer extends FrameBuffer {
|
||||||
|
|
||||||
private configureTexture() {
|
private configureTexture() {
|
||||||
this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture);
|
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.texParameteri(
|
||||||
this.gl.TEXTURE_2D,
|
this.gl.TEXTURE_2D,
|
||||||
this.gl.TEXTURE_MIN_FILTER,
|
this.gl.TEXTURE_MIN_FILTER,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { WebGl2Renderer } from '../webgl2-renderer';
|
|
||||||
import { InfoText } from '../../objects/types/info-text';
|
import { InfoText } from '../../objects/types/info-text';
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/
|
// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export class WebGl2Renderer implements Drawer {
|
||||||
new FragmentShaderOnlyProgram(this.gl, ...shaderSources[1]),
|
new FragmentShaderOnlyProgram(this.gl, ...shaderSources[1]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.distanceFieldFrameBuffer.renderScale = 1;
|
this.distanceFieldFrameBuffer.renderScale = 0.5;
|
||||||
this.lightingFrameBuffer.renderScale = 1;
|
this.lightingFrameBuffer.renderScale = 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -55,7 +55,7 @@ export class WebGl2Renderer implements Drawer {
|
||||||
this.distanceFieldFrameBuffer.render(this.uniforms);
|
this.distanceFieldFrameBuffer.render(this.uniforms);
|
||||||
this.lightingFrameBuffer.render(
|
this.lightingFrameBuffer.render(
|
||||||
this.uniforms,
|
this.uniforms,
|
||||||
this.distanceFieldFrameBuffer.texture
|
this.distanceFieldFrameBuffer.colorTexture
|
||||||
);
|
);
|
||||||
|
|
||||||
this.stopwatch?.stop();
|
this.stopwatch?.stop();
|
||||||
|
|
@ -96,6 +96,7 @@ export class WebGl2Renderer implements Drawer {
|
||||||
worldToDistanceUV,
|
worldToDistanceUV,
|
||||||
cursorPosition,
|
cursorPosition,
|
||||||
ndcToWorld,
|
ndcToWorld,
|
||||||
|
viewBoxSize: this.viewBox.size,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
|
||||||
precision mediump float;
|
precision lowp float;
|
||||||
|
|
||||||
|
|
||||||
#define INFINITY 10000.0
|
#define INFINITY 10000.0
|
||||||
|
|
@ -19,7 +19,7 @@ float lineDistance(
|
||||||
) {
|
) {
|
||||||
vec2 pa = target - start, ba = end - start;
|
vec2 pa = target - start, ba = end - start;
|
||||||
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
|
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) {
|
float getDistance(in vec2 target) {
|
||||||
|
|
@ -36,18 +36,15 @@ float getDistance(in vec2 target) {
|
||||||
return -minDistance;
|
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;
|
in vec2 worldCoordinates;
|
||||||
out vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float distance = getDistance(worldCoordinates);
|
float distance = getDistance(worldCoordinates);
|
||||||
|
const vec3 caveColor = vec3(0.0);
|
||||||
|
const vec3 airColor = vec3(1.0);
|
||||||
fragmentColor = vec4(
|
fragmentColor = vec4(
|
||||||
branchlessTernary(distance, vec3(1.0), vec3(0.0, 1.0, 0.5)),
|
mix(caveColor, airColor, distance),
|
||||||
distance / 128.0 + 0.5
|
distance / 32.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,24 @@ precision mediump float;
|
||||||
|
|
||||||
#define INFINITY 10000.0
|
#define INFINITY 10000.0
|
||||||
#define LIGHT_COUNT 3
|
#define LIGHT_COUNT 3
|
||||||
#define LIGHT_PENETRATION 1000.0
|
#define AMBIENT_LIGHT vec3(0.05)
|
||||||
#define ANTIALIASING_RADIUS 1.0
|
#define LIGHT_DROP 800.0
|
||||||
#define AMBIENT_LIGHT vec3(0.075)
|
#define SHADOW_BIAS 0.01
|
||||||
|
|
||||||
struct Light {
|
struct Light {
|
||||||
vec2 center;
|
vec2 center;
|
||||||
float radius;
|
float radius;
|
||||||
vec3 value;
|
vec3 value;
|
||||||
};
|
}[LIGHT_COUNT] lights;
|
||||||
|
|
||||||
uniform sampler2D distanceTexture;
|
uniform sampler2D distanceTexture;
|
||||||
uniform mat3 worldToDistanceUV;
|
uniform mat3 worldToDistanceUV;
|
||||||
uniform vec2 cursorPosition;
|
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) {
|
float getDistance(in vec2 target, out vec3 color) {
|
||||||
// should avoid this matrix multiplication
|
// should avoid this matrix multiplication
|
||||||
|
|
@ -26,7 +29,7 @@ float getDistance(in vec2 target, out vec3 color) {
|
||||||
|
|
||||||
vec4 values = texture(distanceTexture, targetUV);
|
vec4 values = texture(distanceTexture, targetUV);
|
||||||
color = values.rgb;
|
color = values.rgb;
|
||||||
return (values.a - 0.5) * 128.0;
|
return values.w * 32.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getDistance(in vec2 target) {
|
float getDistance(in vec2 target) {
|
||||||
|
|
@ -34,81 +37,67 @@ float getDistance(in vec2 target) {
|
||||||
vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy;
|
vec2 targetUV = (vec3(target.xy, 1.0) * worldToDistanceUV).xy;
|
||||||
|
|
||||||
vec4 values = texture(distanceTexture, targetUV);
|
vec4 values = texture(distanceTexture, targetUV);
|
||||||
return (values.a - 0.5) * 128.0;
|
return values.w * 32.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createWorld() {
|
void createWorld() {
|
||||||
lights[0] = Light(vec2(600, 700), 40.5, normalize(vec3(1.0)) * 2.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[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[2] = Light(cursorPosition, 52.5, normalize(vec3(0.93, 0.25, 0.5)) * 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getFractionOfLightArriving(
|
float getFractionOfLightArriving(
|
||||||
in vec2 target,
|
in vec2 target,
|
||||||
in vec2 direction,
|
in vec2 direction,
|
||||||
|
in float startingDistance,
|
||||||
in float lightDistance,
|
in float lightDistance,
|
||||||
in float lightRadius
|
in float lightRadius
|
||||||
) {
|
) {
|
||||||
float q = INFINITY;
|
float q = INFINITY;
|
||||||
float rayLength = 0.0;
|
float rayLength = 0.0;
|
||||||
|
|
||||||
|
float movingAverageMeanDistance = startingDistance;
|
||||||
|
|
||||||
for (int j = 0; j < 64; j++) {
|
for (int j = 0; j < 64; j++) {
|
||||||
float minDistance = getDistance(target + direction * rayLength);
|
float minDistance = getDistance(target + direction * rayLength);
|
||||||
q = min(q, minDistance / rayLength);
|
movingAverageMeanDistance = movingAverageMeanDistance / 2.0 + minDistance / 2.0;
|
||||||
rayLength = min(lightDistance, rayLength + max(1.0, minDistance));
|
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) {
|
vec3 getPixelColor(in vec2 worldCoordinates, in vec2 uvCoordinates) {
|
||||||
return a*a;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 getPixelColor(in vec2 worldCoordinates) {
|
|
||||||
vec3 result = vec3(0.0);
|
|
||||||
|
|
||||||
vec3 colorAtPosition;
|
vec3 colorAtPosition;
|
||||||
float startingDistance = getDistance(worldCoordinates, 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++) {
|
for (int i = 0; i < LIGHT_COUNT; i++) {
|
||||||
Light light = lights[i];
|
Light light = lights[i];
|
||||||
|
|
||||||
float lightDistance = distance(worldCoordinates, light.center) - light.radius;
|
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);
|
vec2 lightDirection = normalize(light.center - worldCoordinates);
|
||||||
|
|
||||||
float fractionOfLightArriving = getFractionOfLightArriving(
|
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);
|
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 worldCoordinates;
|
||||||
|
in vec2 uvCoordinates;
|
||||||
out vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
createWorld();
|
createWorld();
|
||||||
// log2 for compenstaion?
|
|
||||||
fragmentColor = vec4(getPixelColor(worldCoordinates), 1.0);
|
fragmentColor = vec4(getPixelColor(worldCoordinates, uvCoordinates), 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
uniform mat3 ndcToWorld;
|
uniform mat3 ndcToWorld;
|
||||||
in vec4 a_position;
|
in vec4 a_position;
|
||||||
out vec2 worldCoordinates;
|
out vec2 worldCoordinates;
|
||||||
|
out vec2 uvCoordinates;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
worldCoordinates = (vec3(a_position.xy, 1.0) * ndcToWorld).xy;
|
worldCoordinates = (vec3(a_position.xy, 1.0) * ndcToWorld).xy;
|
||||||
|
uvCoordinates = ((a_position.xy + vec2(1.0)) / 2.0).xy;
|
||||||
gl_Position = a_position;
|
gl_Position = a_position;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue