101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
#include "cloudshader.h"
|
|
#include "common/noise/cloudnoise.h"
|
|
|
|
|
|
Color CloudShader::shade(const Scene &scene, const Ray &ray) const
|
|
{
|
|
Vector3d hitPoint = ray.origin + ray.direction * ray.length; // Potentially add epsilon
|
|
|
|
// Collect getNoise through the cloud
|
|
float accumulatedNoise = 0.0f;
|
|
float cloudLength = 0.0f; // Length of cloud in ray direction
|
|
|
|
// Get background color behind cloud and information about the clouds length
|
|
Ray cloudRay = ray;
|
|
cloudRay.origin = ray.origin + (ray.length + REFR_EPS) * ray.direction;
|
|
cloudRay.length = INFINITY;
|
|
cloudRay.primitive = nullptr;
|
|
|
|
// Get out of cloud primitive first
|
|
if (ray.primitive->intersect(cloudRay))
|
|
{
|
|
// Get length
|
|
cloudLength = cloudRay.length;
|
|
|
|
// Prepare ray for background color
|
|
cloudRay.setRemainingBounces(cloudRay.getRemainingBounces() + 1);
|
|
cloudRay.origin = cloudRay.origin + (cloudRay.length + REFR_EPS) * cloudRay.direction;
|
|
cloudRay.length = INFINITY;
|
|
cloudRay.primitive = nullptr;
|
|
}
|
|
Color background = scene.traceRay(cloudRay);
|
|
|
|
if (cloudLength == 0.0f) return background; // No cloud or at edge
|
|
|
|
// Get getNoise through cloud
|
|
int const NOISE_SAMPLES = settings.densitySamples;
|
|
float stepWeight = cloudLength / (float) NOISE_SAMPLES;
|
|
for (int i = 0; i < NOISE_SAMPLES; ++i)
|
|
{
|
|
float progress = (float) i / (float) NOISE_SAMPLES;
|
|
Vector3d samplePoint = hitPoint + progress * cloudLength * ray.direction;
|
|
float sampleDensity = getCloudDensity(samplePoint);
|
|
accumulatedNoise += sampleDensity * stepWeight;
|
|
}
|
|
|
|
// Pre-processs accumulated getNoise
|
|
// accumulatedNoise /= (float) NOISE_SAMPLES;
|
|
float cloudDensity = exp(-accumulatedNoise * settings.densityAbsorption);
|
|
|
|
return background * cloudDensity;
|
|
|
|
if (accumulatedNoise < 1 - settings.densityTreshold)
|
|
{
|
|
accumulatedNoise = 0;
|
|
} else
|
|
{
|
|
// Fade out the getNoise
|
|
accumulatedNoise = (accumulatedNoise - (1 - settings.densityTreshold)) / settings.densityTreshold;
|
|
}
|
|
// return accumulatedNoise * Color(1, 1, 1);
|
|
|
|
// Use the getNoise to control the densityTreshold of the clouds
|
|
Color cloud = background * (1.0f - accumulatedNoise) + settings.cloudColor * accumulatedNoise;
|
|
|
|
// Use the getNoise to add some wispy details to the clouds
|
|
cloud += settings.wispyColor * (accumulatedNoise * settings.wispyIntensity);
|
|
|
|
// Add some ambient and diffuse lighting
|
|
// cloud += scene.ambientLight() * material.ambient();
|
|
// for (const auto &light: scene.lights())
|
|
// {
|
|
// Light::Illumination illumination = light->illuminate(scene, ray);
|
|
// if (illumination.distance == 0.0f) continue; // Skip ambient light
|
|
// float diffuse = dotProduct(normal, illumination.direction);
|
|
// cloud += material.cloud() * illumination.cloud * diffuse;
|
|
// }
|
|
return cloud;
|
|
}
|
|
|
|
bool CloudShader::isTransparent() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
CloudShader::CloudShader(const CloudSettings &settings) : settings(settings),
|
|
cloudNoise(CloudNoise(NOISE_SIZE))
|
|
{
|
|
cloudNoise.invert = true;
|
|
}
|
|
|
|
float CloudShader::getCloudDensity(Vector3d point) const
|
|
{
|
|
point /= settings.scale;
|
|
|
|
float density = cloudNoise.getNoise(point);
|
|
|
|
// Treshold
|
|
density = std::max(0.0f, density - settings.densityTreshold) * settings.densityIntensity;
|
|
|
|
return density;
|
|
}
|