153 lines
4.7 KiB
C
153 lines
4.7 KiB
C
#include "suic_lighting.h"
|
|
#include "suic_terrain.h"
|
|
#include <math.h>
|
|
|
|
SuicDirectionalLight suic_light_create(float dir_x, float dir_y, float dir_z,
|
|
float intensity, float ambient) {
|
|
SuicDirectionalLight light = {0};
|
|
light.direction = suic_v3_norm(suic_v3(dir_x, dir_y, dir_z));
|
|
light.color = suic_v3(1.0f, 1.0f, 1.0f);
|
|
light.intensity = intensity;
|
|
light.ambientIntensity = ambient;
|
|
light.shadowBias = 0.005f;
|
|
light.shadowIntensity = 0.4f;
|
|
return light;
|
|
}
|
|
|
|
SuicDirectionalLight suic_light_create_default(void) {
|
|
return suic_light_create(-0.8f, -1.0f, -0.6f, 1.2f, 0.3f);
|
|
}
|
|
|
|
SuicColor suic_light_apply(SuicColor base, SuicVec3 normal,
|
|
SuicDirectionalLight *light) {
|
|
SuicVec3 lightDir = light->direction;
|
|
|
|
/* Diffuse: Lambertian */
|
|
float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y +
|
|
lightDir.z * normal.z));
|
|
|
|
float brightness =
|
|
light->ambientIntensity +
|
|
(diff * light->intensity * (1.0f - light->ambientIntensity));
|
|
|
|
int r = (int)(base.r * brightness);
|
|
int g = (int)(base.g * brightness);
|
|
int b = (int)(base.b * brightness);
|
|
|
|
if (r > 255)
|
|
r = 255;
|
|
if (g > 255)
|
|
g = 255;
|
|
if (b > 255)
|
|
b = 255;
|
|
|
|
return (SuicColor){r, g, b, base.a};
|
|
}
|
|
|
|
float suic_shadow_factor(SuicVec3 worldPos, SuicVec3 lightDir, float maxDist) {
|
|
float distFromLight = fmaxf(0.0f, worldPos.y - 2.0f);
|
|
float shadowIntensity = fmaxf(0.0f, 1.0f - (distFromLight / maxDist));
|
|
return 1.0f - (shadowIntensity * 0.15f);
|
|
}
|
|
|
|
float suic_shadow_temporal(SuicVec3 worldPos, float timePhase) {
|
|
float noiseVal =
|
|
sinf(worldPos.x * 0.5f + timePhase) * cosf(worldPos.z * 0.5f + timePhase);
|
|
return 1.0f + (noiseVal * 0.02f);
|
|
}
|
|
|
|
SuicColor suic_light_apply_shadows(SuicColor base, SuicVec3 normal,
|
|
SuicVec3 worldPos,
|
|
SuicDirectionalLight *light) {
|
|
float shadowFactor = suic_shadow_factor(worldPos, light->direction, 10.0f);
|
|
float adjustedIntensity = light->intensity * shadowFactor;
|
|
|
|
SuicVec3 lightDir = light->direction;
|
|
float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y +
|
|
lightDir.z * normal.z));
|
|
|
|
float brightness =
|
|
light->ambientIntensity +
|
|
(diff * adjustedIntensity * (1.0f - light->ambientIntensity));
|
|
|
|
int r = (int)(base.r * brightness);
|
|
int g = (int)(base.g * brightness);
|
|
int b = (int)(base.b * brightness);
|
|
|
|
if (r > 255)
|
|
r = 255;
|
|
if (g > 255)
|
|
g = 255;
|
|
if (b > 255)
|
|
b = 255;
|
|
|
|
return (SuicColor){r, g, b, base.a};
|
|
}
|
|
|
|
float suic_ao_calculate(SuicVec3 worldPos, SuicVec3 normal) {
|
|
float sampleRadius = 3.0f;
|
|
float aoAccum = 0.0f;
|
|
int numSamples = 8;
|
|
float centerHeight = worldPos.y;
|
|
float pi = 3.14159265f;
|
|
|
|
for (int i = 0; i < numSamples; i++) {
|
|
float angle = (2.0f * pi * (float)i) / (float)numSamples;
|
|
float sx = worldPos.x + cosf(angle) * sampleRadius;
|
|
float sz = worldPos.z + sinf(angle) * sampleRadius;
|
|
float sh = suic_terrain_height(sx, sz);
|
|
|
|
float heightDiff = sh - centerHeight;
|
|
if (heightDiff > 0.1f) {
|
|
float aoAmount = fminf(1.0f, heightDiff / 2.0f);
|
|
aoAccum += aoAmount;
|
|
}
|
|
}
|
|
|
|
float aoFactor = 1.0f - (aoAccum / (float)numSamples) * 0.6f;
|
|
return fmaxf(0.2f, aoFactor);
|
|
}
|
|
|
|
SuicColor suic_light_apply_phong(SuicColor base, SuicVec3 normal,
|
|
SuicVec3 worldPos, SuicVec3 camPos,
|
|
SuicDirectionalLight *light) {
|
|
SuicVec3 lightDir = suic_v3_norm(light->direction);
|
|
SuicVec3 normal_n = suic_v3_norm(normal);
|
|
SuicVec3 viewDir = suic_v3_norm(suic_v3_sub(camPos, worldPos));
|
|
|
|
/* Diffuse */
|
|
float diffuse = fmaxf(0.0f, -suic_v3_dot(lightDir, normal_n));
|
|
|
|
/* Specular: Blinn-Phong */
|
|
SuicVec3 negLight = suic_v3(-lightDir.x, -lightDir.y, -lightDir.z);
|
|
SuicVec3 halfVec = suic_v3_norm(suic_v3_add(suic_v3_norm(negLight), viewDir));
|
|
float specular =
|
|
powf(fmaxf(0.0f, suic_v3_dot(halfVec, normal_n)), 32.0f) * 0.5f;
|
|
|
|
/* Ambient occlusion */
|
|
float ao = suic_ao_calculate(worldPos, normal_n);
|
|
|
|
/* Shadow */
|
|
float shadowFactor = suic_shadow_factor(worldPos, light->direction, 10.0f);
|
|
|
|
/* Combine */
|
|
float brightness = light->ambientIntensity * ao;
|
|
brightness += diffuse * light->intensity * shadowFactor *
|
|
(1.0f - light->ambientIntensity) * ao;
|
|
brightness += specular * light->intensity * shadowFactor * 0.6f;
|
|
|
|
brightness = fminf(1.0f, brightness);
|
|
|
|
int r = (int)(base.r * brightness);
|
|
int g = (int)(base.g * brightness);
|
|
int b = (int)(base.b * brightness);
|
|
|
|
if (r > 255)
|
|
r = 255;
|
|
if (g > 255)
|
|
g = 255;
|
|
if (b > 255)
|
|
b = 255;
|
|
|
|
return (SuicColor){r, g, b, base.a};
|
|
}
|