Some experiments for Cloud lighting

This commit is contained in:
Maximilian Giller 2023-01-24 19:38:12 +01:00
parent d7d38944ea
commit 7ec5a8a5f4
3 changed files with 63 additions and 2 deletions

View file

@ -29,7 +29,7 @@ int main()
scene.setBackgroundColor(Color(0.529f, 0.808f, 0.922f));
// Add lights
auto mainLight = std::make_shared<SunLight>(Vector3d(1.0f, -1.0f, -1.0f), 10.0f);
auto mainLight = std::make_shared<SunLight>(Vector3d(-1.0f, -0.5f, -1.0f), 10.0f);
scene.add(mainLight);
scene.add(std::make_shared<AmbientLight>(0.3f));

View file

@ -38,6 +38,7 @@ Color CloudShader::shade(const Scene &scene, const Ray &ray) const
// Step through cloud
float transmittance = 1.0f;
Color cloudColor = Color(1, 1, 1);
for (int i = 0; i < noiseSamples; ++i)
{
// Get sample point
@ -45,8 +46,10 @@ Color CloudShader::shade(const Scene &scene, const Ray &ray) const
// Get data at point
float sampleDensity = getCloudDensity(samplePoint) * stepLength;
// cloudColor += lightMarch(scene, samplePoint, ray);
transmittance *= exp(-sampleDensity * stepLength * settings.densityAbsorption);
if (transmittance <= TRANSMITTANCE_BREAK) break; // No need to continue
}
// Add some ambient and diffuse lighting
@ -59,7 +62,7 @@ Color CloudShader::shade(const Scene &scene, const Ray &ray) const
// cloud += material.cloud() * illumination.cloud * diffuse;
// }
return background * transmittance + (1.0f - transmittance) * settings.cloudColor;
return background * transmittance + (1.0f - transmittance) * cloudColor;
}
bool CloudShader::isTransparent() const
@ -84,3 +87,55 @@ float CloudShader::getCloudDensity(Vector3d point) const
return density;
}
Color CloudShader::lightMarch(const Scene &scene, Vector3d position, const Ray &ray) const
{
Color cloudColor;
// For alle lights
for (const auto &light: scene.lights())
{
auto illumination = light->illuminate(scene, position);
// Get light direction
Vector3d lightDirection = normalized(illumination.direction); // Points from surface to light
// Get length of remaining cloud in light direction
float cloudLength = 0.0f;
Ray cloudRay = ray;
cloudRay.origin = position;
cloudRay.direction = lightDirection;
cloudRay.length = INFINITY;
cloudRay.primitive = nullptr;
// Find other end of cloud
if (!ray.primitive->intersect(cloudRay) || cloudRay.length == INFINITY)
{
// No cloud or at edge
continue;
}
cloudLength = cloudRay.length;
// Calculate step length
int lightSamples = settings.lightSamples;
float stepLength = cloudLength / lightSamples;
// Step through cloud
float transmittance = 0.0f;
for (int i = 0; i < lightSamples; ++i)
{
Vector3d samplePoint = position + i * stepLength * lightDirection;
float density = getCloudDensity(samplePoint) * stepLength;
transmittance *= exp(-density * settings.densityAbsorption);
if (transmittance <= TRANSMITTANCE_BREAK) break; // No need to continue
}
// float lightAbsorption = dotProduct(lightDirection, ray.direction); // Approaches 1 when light is parallel to ray
cloudColor += transmittance * illumination.color;
}
return cloudColor;
}

View file

@ -3,19 +3,23 @@
#include "scene/scene.h"
#include "shader.h"
#include "light/light.h"
#include "primitive/primitive.h"
#include "common/noise/worleynoise.h"
int const NOISE_SIZE = 128;
int const TRANSMITTANCE_BREAK = 0.01f; // If transmittance goes below this limit, the cloud is considered opaque
struct CloudSettings
{
int densitySamples = 100;
int lightSamples = 25;
float scale = 10;
float densityTreshold = 0.55f;
float densityIntensity = 2.5f;
float densityAbsorption = 2;
Color cloudColor = Color(1, 1, 1);
float darknessThreshold = 0.1f;
};
class CloudShader : public Shader
@ -35,6 +39,8 @@ private:
Noise cloudNoise;
float getCloudDensity(Vector3d point) const;
Color lightMarch(const Scene &scene, Vector3d position, const Ray &ray) const;
};