decla-red/frontend/src/scripts/drawing/shaders/lights-shading-fs.glsl
2020-08-18 09:40:51 +02:00

127 lines
4 KiB
GLSL

#version 300 es
precision mediump float;
#define INFINITY 1000.0
#define LIGHT_DROP 500.0
#define AMBIENT_LIGHT vec3(0.15)
#define CIRCLE_LIGHT_COUNT {circleLightCount}
#define POINT_LIGHT_COUNT {pointLightCount}
#define EDGE_SMOOTHING {edgeSmoothing}
uniform sampler2D distanceTexture;
uniform vec2 viewBoxSize;
vec3[4] colors = vec3[4](
vec3(0.5),
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
float getDistance(in vec2 target, out vec3 color) {
vec4 values = texture(distanceTexture, target);
color = colors[int(values[1])];
return values[0];
}
float getDistance(in vec2 target) {
return texture(distanceTexture, target)[0];
}
#if CIRCLE_LIGHT_COUNT > 0
uniform struct CircleLight {
vec2 center;
float radius;
vec3 value;
}[CIRCLE_LIGHT_COUNT] circleLights;
in vec2[CIRCLE_LIGHT_COUNT] circleLightDirections;
#endif
#if POINT_LIGHT_COUNT > 0
uniform struct PointLight {
vec2 center;
float radius;
vec3 value;
}[POINT_LIGHT_COUNT] pointLights;
in vec2[POINT_LIGHT_COUNT] pointLightDirections;
#endif
in vec2 worldCoordinates;
in vec2 uvCoordinates;
out vec4 fragmentColor;
void main() {
vec3 colorAtPosition;
float startingDistance = getDistance(uvCoordinates, colorAtPosition);
vec3 lighting = AMBIENT_LIGHT;
#if CIRCLE_LIGHT_COUNT > 0
for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) {
float lightCenterDistance = distance(circleLights[i].center, worldCoordinates);
vec3 lightColorAtPosition = circleLights[i].value / pow(
lightCenterDistance / LIGHT_DROP + 1.0, 2.0
);
float q = INFINITY;
float rayLength = startingDistance;
float exponentialDecayDistance = rayLength;
vec2 direction = normalize(circleLightDirections[i]) / viewBoxSize;
for (int j = 0; j < 48; j++) {
if (rayLength > lightCenterDistance - circleLights[i].radius) {
rayLength = lightCenterDistance - circleLights[i].radius;
float minDistance = getDistance(uvCoordinates + direction * rayLength);
exponentialDecayDistance = (exponentialDecayDistance + minDistance) / 2.0;
q = min(q, minDistance / rayLength);
lighting += lightColorAtPosition * clamp(
q / circleLights[i].radius * (lightCenterDistance + 1.0), 0.0, 1.0
);
break;
}
float minDistance = getDistance(uvCoordinates + direction * rayLength);
exponentialDecayDistance = (exponentialDecayDistance + minDistance) / 2.0;
q = min(q, exponentialDecayDistance / rayLength);
rayLength += minDistance;
}
}
#endif
#if POINT_LIGHT_COUNT > 0
for (int i = 0; i < POINT_LIGHT_COUNT; i++) {
float lightDistance = distance(pointLights[i].center, worldCoordinates);
vec3 lightColorAtPosition = mix(
pointLights[i].value,
vec3(0.0),
sqrt(clamp(lightDistance / pointLights[i].radius, 0.0, 1.0))
);
float q = INFINITY;
float rayLength = startingDistance;
float exponentialDecayDistance = startingDistance;
vec2 direction = normalize(pointLightDirections[i]) / viewBoxSize;
for (int j = 0; j < 48; j++) {
if (rayLength > lightDistance) {
lighting += lightColorAtPosition * step(0.0, q);
break;
}
float minDistance = getDistance(uvCoordinates + direction * rayLength);
exponentialDecayDistance = (exponentialDecayDistance + minDistance) / 2.0;
q = min(q, exponentialDecayDistance);
rayLength += minDistance;
}
}
#endif
fragmentColor = vec4(colorAtPosition * lighting * step(0.0, startingDistance), 1.0);
}