Improved clouds lighting

This commit is contained in:
Michaël Lemaire 2016-02-01 20:38:29 +01:00
parent 2878f1f157
commit a54c8d5217
32 changed files with 188 additions and 134 deletions

View file

@ -22,3 +22,12 @@ double Maths::smoothstep(double edge0, double edge1, double x) {
x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return x * x * (3.0 - 2.0 * x);
}
double Maths::zeroPoint(double segment_length, double edge0, double edge1) {
double diff = edge1 - edge0;
if (diff == 0.0) {
return 0.0;
} else {
return -edge0 * segment_length / diff;
}
}

View file

@ -26,6 +26,13 @@ class BASICSSHARED_EXPORT Maths {
*/
static double smoothstep(double edge0, double edge1, double x);
/**
* Find the length in a segment (with border values "edge0" and "edge1"), at which the value crosses 0.
*
* The length is not normalized (the middle of a segment of length 0.2 is 0.1).
*/
static double zeroPoint(double segment_length, double edge0, double edge1);
static constexpr double PI = 3.141592653589793238462643383279;
static constexpr double PI_2 = PI / 2.0;
static constexpr double PI_4 = PI / 4.0;

View file

@ -27,51 +27,15 @@ typedef struct {
double w;
} Grad4;
static Grad3 _grad3[] = {{1, 1, 0},
{-1, 1, 0},
{1, -1, 0},
{-1, -1, 0},
{1, 0, 1},
{-1, 0, 1},
{1, 0, -1},
{-1, 0, -1},
{0, 1, 1},
{0, -1, 1},
{0, 1, -1},
{0, -1, -1}};
static Grad3 _grad3[] = {{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0}, {1, 0, 1}, {-1, 0, 1},
{1, 0, -1}, {-1, 0, -1}, {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}};
static Grad4 _grad4[] = {{0, 1, 1, 1},
{0, 1, 1, -1},
{0, 1, -1, 1},
{0, 1, -1, -1},
{0, -1, 1, 1},
{0, -1, 1, -1},
{0, -1, -1, 1},
{0, -1, -1, -1},
{1, 0, 1, 1},
{1, 0, 1, -1},
{1, 0, -1, 1},
{1, 0, -1, -1},
{-1, 0, 1, 1},
{-1, 0, 1, -1},
{-1, 0, -1, 1},
{-1, 0, -1, -1},
{1, 1, 0, 1},
{1, 1, 0, -1},
{1, -1, 0, 1},
{1, -1, 0, -1},
{-1, 1, 0, 1},
{-1, 1, 0, -1},
{-1, -1, 0, 1},
{-1, -1, 0, -1},
{1, 1, 1, 0},
{1, 1, -1, 0},
{1, -1, 1, 0},
{1, -1, -1, 0},
{-1, 1, 1, 0},
{-1, 1, -1, 0},
{-1, -1, 1, 0},
{-1, -1, -1, 0}};
static Grad4 _grad4[] = {
{0, 1, 1, 1}, {0, 1, 1, -1}, {0, 1, -1, 1}, {0, 1, -1, -1}, {0, -1, 1, 1}, {0, -1, 1, -1}, {0, -1, -1, 1},
{0, -1, -1, -1}, {1, 0, 1, 1}, {1, 0, 1, -1}, {1, 0, -1, 1}, {1, 0, -1, -1}, {-1, 0, 1, 1}, {-1, 0, 1, -1},
{-1, 0, -1, 1}, {-1, 0, -1, -1}, {1, 1, 0, 1}, {1, 1, 0, -1}, {1, -1, 0, 1}, {1, -1, 0, -1}, {-1, 1, 0, 1},
{-1, 1, 0, -1}, {-1, -1, 0, 1}, {-1, -1, 0, -1}, {1, 1, 1, 0}, {1, 1, -1, 0}, {1, -1, 1, 0}, {1, -1, -1, 0},
{-1, 1, 1, 0}, {-1, 1, -1, 0}, {-1, -1, 1, 0}, {-1, -1, -1, 0}};
static short _permutations[] = {
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142,

View file

@ -45,7 +45,8 @@ class DEFINITIONSHARED_EXPORT CloudLayerDefinition : public DefinitionNode {
CUMULONIMBUS,
CIRROCUMULUS,
CIRROSTRATUS,
CIRRUS
CIRRUS,
_COUNT
} CloudsType;
public:

View file

@ -10,10 +10,10 @@ SurfaceMaterial::SurfaceMaterial() : SurfaceMaterial(COLOR_BLACK) {
SurfaceMaterial::SurfaceMaterial(const Color &color) {
base = new Color(color);
ambient = 0.0;
hardness = 0.5;
reflection = 0.0;
shininess = 0.0;
receive_shadows = 1.0;
}
SurfaceMaterial::SurfaceMaterial(const SurfaceMaterial &other) : SurfaceMaterial(COLOR_BLACK) {
@ -38,29 +38,27 @@ void SurfaceMaterial::setColor(double r, double g, double b, double a) {
void SurfaceMaterial::save(PackStream *stream) const {
base->save(stream);
stream->write(&ambient);
stream->write(&hardness);
stream->write(&reflection);
stream->write(&shininess);
stream->write(&receive_shadows);
}
void SurfaceMaterial::load(PackStream *stream) {
base->load(stream);
stream->read(&ambient);
stream->read(&hardness);
stream->read(&reflection);
stream->read(&shininess);
stream->read(&receive_shadows);
}
void SurfaceMaterial::copy(SurfaceMaterial *destination) const {
*destination->base = *base;
destination->ambient = ambient;
destination->hardness = hardness;
destination->reflection = reflection;
destination->shininess = shininess;
destination->receive_shadows = receive_shadows;
destination->validate();
}

View file

@ -25,11 +25,10 @@ class DEFINITIONSHARED_EXPORT SurfaceMaterial {
public:
Color *base;
double ambient;
double hardness;
double reflection;
double shininess;
double receive_shadows;
};
}
}

View file

@ -127,8 +127,7 @@ int main(int argc, char **argv) {
scenery->autoPreset();
}
Logs::debug("CommandLine") << "Rendered scenery :" << endl
<< scenery->toString() << endl;
Logs::debug("CommandLine") << "Rendered scenery :" << endl << scenery->toString() << endl;
TimeManager time;
time.setWind(conf_wind_x, conf_wind_z);

View file

@ -152,6 +152,7 @@ static void testCloudQuality() {
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(600, 800);
renderer.getGodRaysSampler()->setEnabled(false);
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(&rasterizer);
for (int i = 0; i < 6; i++) {
@ -463,14 +464,11 @@ static void testCloudsLighting() {
FakeModel(CloudLayerDefinition *layer, double scale) : BaseCloudsModel(layer), scale(scale) {
}
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override {
*min_altitude = -scale;
*max_altitude = scale;
*min_altitude = 10.0 - scale;
*max_altitude = 10.0 + scale;
}
virtual void getDetailRange(double *min_step, double *max_step) const override {
*min_step = *max_step = scale * 0.01;
}
virtual double getDensity(const Vector3 &location) const override {
return Maths::smoothstep(0.0, 0.2, 1.0 - location.getNorm() / scale);
virtual double getDensity(const Vector3 &location, double) const override {
return 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale;
}
double scale;
};
@ -482,8 +480,8 @@ static void testCloudsLighting() {
virtual Color processPixel(int, int, double relx, double rely) const override {
auto cloud_renderer = renderer->getCloudsRenderer();
auto atmo_renderer = renderer->getAtmosphereRenderer();
return cloud_renderer->getColor(Vector3(relx * scale * 1.2, rely * scale * 1.2, scale),
Vector3(relx * scale * 1.2, rely * scale * 1.2, -scale),
return cloud_renderer->getColor(Vector3(relx * scale * 1.2, 10.0 + rely * scale * 1.2, scale),
Vector3(relx * scale * 1.2, 10.0 + rely * scale * 1.2, -scale),
atmo_renderer->getSkyColor(Vector3(relx, rely, 1.0).normalize()).final);
}
virtual int prepareRasterization() override {
@ -500,15 +498,16 @@ static void testCloudsLighting() {
Scenery scenery;
scenery.autoPreset(1);
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
scenery.getCamera()->setTarget(VECTOR_ZERO);
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 5.0));
scenery.getCamera()->setLocation(Vector3(0.0, 10.0, 11.0));
CloudLayerDefinition layer(NULL, "test");
scenery.getClouds()->clear();
scenery.getClouds()->addLayer(layer);
SoftwareCanvasRenderer renderer(&scenery);
FakeRasterizer rasterizer(&renderer, 10.0);
FakeRasterizer rasterizer(&renderer, 5.0);
renderer.setSize(800, 800);
renderer.setSoloRasterizer(&rasterizer);
renderer.getGodRaysSampler()->setEnabled(false);
@ -522,6 +521,36 @@ static void testCloudsLighting() {
startTestRender(&renderer, "clouds_lighting_night");
}
static void testCloudModels() {
Scenery scenery;
scenery.autoPreset(1);
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
CloudLayerDefinition layer(NULL, "test");
layer.altitude = 1.0;
scenery.getClouds()->clear();
scenery.getClouds()->addLayer(layer);
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(800, 600);
renderer.getGodRaysSampler()->setEnabled(false);
for (int i = CloudLayerDefinition::STRATOCUMULUS; i < CloudLayerDefinition::_COUNT; i++) {
// FIXME Test all
layer.type = static_cast<CloudLayerDefinition::CloudsType>(i);
layer.validate();
renderer.getCloudsRenderer()->update();
auto model = renderer.getCloudsRenderer()->getLayerModel(0);
double minalt, maxalt;
model->getAltitudeRange(&minalt, &maxalt);
double offset = 8.0;
scenery.getCamera()->setLocation(Vector3(0.0, minalt - offset, 0.0));
scenery.getCamera()->setTarget(Vector3(0.0, minalt, offset));
startTestRender(&renderer, "clouds_model", i);
}
}
void runTestSuite() {
testNoise();
testTextures();

View file

@ -141,8 +141,7 @@ void MainModelerWindow::keyReleaseEvent(QKeyEvent *event) {
} else if (event->key() == Qt::Key_F6) {
render_process->showPreviousRender();
} else if (event->key() == Qt::Key_F12) {
Logs::warning("UI") << "Current scenery dump:" << endl
<< scenery->toString() << endl;
Logs::warning("UI") << "Current scenery dump:" << endl << scenery->toString() << endl;
} else if (event->key() == Qt::Key_N) {
if (event->modifiers() & Qt::ControlModifier) {
newFile();

View file

@ -128,11 +128,11 @@ void RenderProcess::startQuickRender() {
}
void RenderProcess::startMediumRender() {
startRender(window->getScenery(), RenderConfig(800, 450, 1, 5));
startRender(window->getScenery(), RenderConfig(800, 450, 1, 7));
}
void RenderProcess::startFinalRender() {
startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 8));
startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 10));
}
void RenderProcess::showPreviousRender() {

View file

@ -117,8 +117,7 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(cons
case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON:
result = model->applyAerialPerspective(location, base);
break;
default:
;
default:;
}
// Apply god rays ponderation

View file

@ -13,6 +13,7 @@
#include "clouds/BaseCloudsModel.h"
#include "SurfaceMaterial.h"
#include "Logs.h"
#include "Maths.h"
#include "FloatNode.h"
struct CloudSegment {
@ -24,10 +25,6 @@ struct CloudSegment {
CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer *parent) : BaseCloudLayerRenderer(parent) {
}
static inline double _getDistanceToBorder(BaseCloudsModel *model, const Vector3 &position) {
return model->getDensity(position);
}
/**
* Go through the cloud layer to find segments (parts of the lookup that are inside the cloud).
*
@ -47,13 +44,14 @@ static inline double _getDistanceToBorder(BaseCloudsModel *model, const Vector3
*/
int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction,
int max_segments, double max_inside_length, double max_total_length,
double *inside_length, double *total_length, CloudSegment *out_segments) {
double *inside_length, double *total_length, CloudSegment *out_segments,
double base_detail) {
double ymin, ymax;
int inside, segment_count;
double current_total_length, current_inside_length;
double step_length, segment_length;
double min_step, max_step;
double noise_distance;
double noise_distance, previous_noise_distance;
Vector3 walker, step, segment_start, offset;
double render_precision;
@ -68,20 +66,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
double distance = parent->getCameraLocation().sub(start).getNorm();
render_precision = min_step + (max_step - min_step) * min(distance / (quality + 0.1), 100.0) * 0.01;
/*double verticality = fabs(direction.y);
if (verticality > 0.5) {
render_precision *= 1.0 - 1.8 * (verticality - 0.5);
}*/
segment_count = 0;
current_total_length = 0.0;
current_inside_length = 0.0;
segment_length = 0.0;
walker = start;
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
noise_distance = _getDistanceToBorder(model, start.add(offset)) * render_precision;
inside = 0;
noise_distance = model->getDensity(start.add(offset), base_detail);
previous_noise_distance = noise_distance;
inside = noise_distance > 0.0;
if (inside) {
segment_start = start;
}
step = direction.scale(render_precision);
bool stop = false;
do {
walker = walker.add(step);
step_length = step.getNorm();
noise_distance = _getDistanceToBorder(model, walker.add(offset)) * render_precision;
noise_distance = stop ? 0.0 : model->getDensity(walker.add(offset), base_detail);
current_total_length += step_length;
if (noise_distance > 0.0) {
@ -89,23 +97,26 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
// inside the cloud
segment_length += step_length;
current_inside_length += step_length;
step = direction.scale((noise_distance < render_precision) ? render_precision : noise_distance);
step = direction.scale((noise_distance < 1.0) ? render_precision : (noise_distance * render_precision));
} else {
// entering the cloud
inside = 1;
segment_length = 0.0;
segment_start = walker;
segment_length = step_length - Maths::zeroPoint(step_length, previous_noise_distance, noise_distance);
assert(segment_length >= 0.0 && segment_length <= step_length);
segment_start = walker.add(direction.scale(-segment_length));
current_inside_length += segment_length;
step = direction.scale(render_precision);
}
} else {
if (inside) {
// exiting the cloud
segment_length += step_length;
current_inside_length += step_length;
double exit_length = Maths::zeroPoint(step_length, previous_noise_distance, noise_distance);
assert(exit_length >= 0.0);
segment_length += exit_length;
current_inside_length += exit_length;
out_segments->start = segment_start;
out_segments->end = walker;
out_segments->end = walker.add(direction.scale(exit_length - step_length));
out_segments->length = segment_length;
out_segments++;
if (++segment_count >= max_segments) {
@ -116,19 +127,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
step = direction.scale(render_precision);
} else {
// searching for a cloud
step = direction.scale((noise_distance > -render_precision) ? render_precision : -noise_distance);
step =
direction.scale((noise_distance > -1.0) ? render_precision : (-noise_distance * render_precision));
}
}
render_precision *= 1.0 + 0.001 / (quality + 0.1);
} while (inside || (walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 &&
current_total_length < max_total_length && current_inside_length < max_inside_length));
previous_noise_distance = noise_distance;
stop = not(walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 && current_total_length < max_total_length &&
current_inside_length < max_inside_length);
} while (inside or not stop);
*total_length = current_total_length;
*inside_length = current_inside_length;
return segment_count;
}
static inline Vector3 _getPseudoNormal(const BaseCloudsModel *model, const Vector3 &base, const Vector3 &direction) {
double precision = 0.3;
double base_density = model->getDensity(base, precision); // TODO keep
double density = model->getDensity(base.add(direction.scale(precision * 10.0)), precision);
double diff = base_density - density;
return direction.scale(diff > 0.0 ? diff : 0.0);
}
Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) {
int i, segment_count;
double max_length, total_length, inside_length;
@ -151,27 +173,32 @@ Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &e
model->getAltitudeRange(&ymin, &ymax);
double transparency_depth = (ymax - ymin);
SurfaceMaterial material(COLOR_WHITE.scaled(5.0));
material.hardness = 1.0;
material.reflection = 0.0;
material.shininess = 0.0;
SurfaceMaterial material(COLOR_WHITE.scaled(8.0));
material.ambient = 0.8;
material.hardness = 0.0;
material.reflection = 0.2;
material.shininess = 3.0;
material.validate();
segment_count = findSegments(model, start, direction, 30, transparency_depth, max_length, &inside_length,
&total_length, segments);
&total_length, segments, 0.001);
for (i = segment_count - 1; i >= 0; i--) {
col = parent->applyLightingToSurface(segments[i].start, VECTOR_UP, material);
Vector3 normal = VECTOR_ZERO;
const Vector3 &location = segments[i].start;
normal = normal.add(_getPseudoNormal(model, location, VECTOR_UP));
normal = normal.add(_getPseudoNormal(model, location, VECTOR_DOWN));
normal = normal.add(_getPseudoNormal(model, location, VECTOR_EAST));
normal = normal.add(_getPseudoNormal(model, location, VECTOR_WEST));
normal = normal.add(_getPseudoNormal(model, location, VECTOR_NORTH));
normal = normal.add(_getPseudoNormal(model, location, VECTOR_SOUTH));
col = parent->applyLightingToSurface(location, normal.normalize(), material);
col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth);
result.mask(col);
}
// Opacify when hitting inside_length limit
if (inside_length >= transparency_depth) {
result.a = 1.0;
} else if (inside_length >= transparency_depth * 0.8) {
result.a += (1.0 - result.a) * ((inside_length - transparency_depth * 0.8) / (transparency_depth * 0.2));
}
// Opacity
result.a = Maths::smoothstep(0.0, transparency_depth, inside_length);
// Apply aerial perspective
if (result.a > 0.00001) {
@ -196,14 +223,14 @@ bool CloudBasicLayerRenderer::alterLight(BaseCloudsModel *model, LightComponent
direction = light->direction.scale(-1.0);
end = location.add(direction.scale(10000.0));
if (not optimizeSearchLimits(model, &start, &end)) {
return false;
return true;
}
double ymin, ymax;
model->getAltitudeRange(&ymin, &ymax);
double light_traversal = (ymax - ymin) * 0.8 * light->color.getPower();
findSegments(model, start, direction, 30, light_traversal, end.sub(start).getNorm(), &inside_depth, &total_depth,
segments);
segments, 0.1);
if (light_traversal < 0.0001) {
factor = 0.0;

View file

@ -27,7 +27,7 @@ class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer : public BaseCloudLayerRende
private:
int findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction, int max_segments,
double max_inside_length, double max_total_length, double *inside_length, double *total_length,
CloudSegment *out_segments);
CloudSegment *out_segments, double base_detail);
};
}
}

View file

@ -85,6 +85,7 @@ void CloudsRenderer::update() {
case CloudLayerDefinition::ALTOSTRATUS:
case CloudLayerDefinition::CIRROCUMULUS:
case CloudLayerDefinition::CIRROSTRATUS:
case CloudLayerDefinition::_COUNT:
model = new BaseCloudsModel(layer);
break;
}

View file

@ -119,9 +119,14 @@ double GodRaysSampler::getCachedLight(const Vector3 &location) {
}
// Hit cache
double p[8] = {getCache(ix, iy, iz), getCache(ix + 1, iy, iz), getCache(ix + 1, iy + 1, iz),
getCache(ix, iy + 1, iz), getCache(ix, iy, iz + 1), getCache(ix + 1, iy, iz + 1),
getCache(ix + 1, iy + 1, iz + 1), getCache(ix, iy + 1, iz + 1)};
double p[8] = {getCache(ix, iy, iz),
getCache(ix + 1, iy, iz),
getCache(ix + 1, iy + 1, iz),
getCache(ix, iy + 1, iz),
getCache(ix, iy, iz + 1),
getCache(ix + 1, iy, iz + 1),
getCache(ix + 1, iy + 1, iz + 1),
getCache(ix, iy + 1, iz + 1)};
return Interpolation::trilinear(p, (x - sampling_step * double(ix)) / sampling_step,
(y - sampling_step * double(iy)) / sampling_step,
(z - sampling_step * double(iz)) / sampling_step);

View file

@ -7,6 +7,7 @@
#include "LightSource.h"
#include "Color.h"
#include "SurfaceMaterial.h"
#include "Logs.h"
LightingManager::LightingManager() {
specularity = true;
@ -92,21 +93,16 @@ void LightingManager::setFiltering(bool enabled) {
Color LightingManager::applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location,
const Vector3 &normal, const SurfaceMaterial &material) {
Color result, light_color;
double normal_norm;
Vector3 direction_inv;
light_color = component.color;
direction_inv = component.direction.normalize().scale(-1.0);
normal_norm = normal.getNorm();
if (normal_norm > 1.0) {
normal_norm = 1.0;
}
normal.normalize();
result = COLOR_BLACK;
/* diffused light */
double diffuse = direction_inv.dotProduct(normal.normalize());
double diffuse = direction_inv.dotProduct(normal);
double sign = (diffuse < 0.0) ? -1.0 : 1.0;
if (material.hardness <= 0.5) {
double hardness = material.hardness * 2.0;
@ -115,7 +111,9 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons
double hardness = (material.hardness - 0.5) * 2.0;
diffuse = (1.0 - hardness) * diffuse + hardness * sign * sqrt(fabs(diffuse));
}
diffuse = (diffuse + (1.0 - normal_norm)) / (1.0 + (1.0 - normal_norm));
if (material.ambient > 0.0) {
diffuse = material.ambient + (1.0 - material.ambient) * diffuse;
}
if (diffuse > 0.0) {
result.r += diffuse * material.base->r * light_color.r;
result.g += diffuse * material.base->g * light_color.g;
@ -123,12 +121,12 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons
}
/* specular reflection */
if (material.shininess > 0.0 && material.reflection > 0.0 && component.reflection > 0.0) {
if (sign > 0.0 && material.shininess > 0.0 && material.reflection > 0.0 && component.reflection > 0.0) {
Vector3 view = location.sub(eye).normalize();
Vector3 reflect = direction_inv.sub(normal.scale(2.0 * direction_inv.dotProduct(normal)));
double specular = reflect.dotProduct(view);
if (specular > 0.0) {
specular = pow(specular, material.shininess) * material.reflection * component.reflection * normal_norm;
specular = pow(specular, material.shininess) * material.reflection * component.reflection;
if (specular > 0.0) {
result.r += specular * light_color.r;
result.g += specular * light_color.g;

View file

@ -33,6 +33,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery) : SoftwareRende
new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION));
current_work = NULL;
setQuality(0.5);
}
SoftwareCanvasRenderer::~SoftwareCanvasRenderer() {

View file

@ -29,7 +29,7 @@ double BaseCloudsModel::getProbability(const Vector3 &, double) const {
return 1.0;
}
double BaseCloudsModel::getDensity(const Vector3 &) const {
double BaseCloudsModel::getDensity(const Vector3 &, double) const {
return 0.0;
}

View file

@ -21,7 +21,7 @@ class SOFTWARESHARED_EXPORT BaseCloudsModel {
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const;
virtual void getDetailRange(double *min_step, double *max_step) const;
virtual double getProbability(const Vector3 &location, double radius) const;
virtual double getDensity(const Vector3 &location) const;
virtual double getDensity(const Vector3 &location, double precision) const;
virtual Color filterLight(const Color &light, double length, double density) const;
virtual Color applyLightExit(const Color &light, const Vector3 &light_direction,
const Vector3 &direction_to_eye) const;

View file

@ -32,7 +32,7 @@ void CloudModelAltoCumulus::getAltitudeRange(double *min_altitude, double *max_a
*max_altitude = *min_altitude + 18.0 * layer->scaling;
}
double CloudModelAltoCumulus::getDensity(const Vector3 &location) const {
double CloudModelAltoCumulus::getDensity(const Vector3 &location, double) const {
double val;
double min_altitude, max_altitude;
double noise_scaling = 18.0 * layer->scaling;

View file

@ -16,7 +16,7 @@ class CloudModelAltoCumulus : public BaseCloudsModel {
virtual void update() override;
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
virtual double getDensity(const Vector3 &location) const override;
virtual double getDensity(const Vector3 &location, double precision) const override;
private:
NoiseGenerator *noise;

View file

@ -30,7 +30,7 @@ void CloudModelCirrus::getAltitudeRange(double *min_altitude, double *max_altitu
*max_altitude = *min_altitude + 20.0 * layer->scaling;
}
double CloudModelCirrus::getDensity(const Vector3 &location) const {
double CloudModelCirrus::getDensity(const Vector3 &location, double) const {
double val;
double min_altitude, max_altitude;
double noise_scaling = 30.0 * layer->scaling;

View file

@ -16,7 +16,7 @@ class CloudModelCirrus : public BaseCloudsModel {
virtual void update() override;
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
virtual double getDensity(const Vector3 &location) const override;
virtual double getDensity(const Vector3 &location, double precision) const override;
private:
NoiseGenerator *noise;

View file

@ -37,7 +37,7 @@ void CloudModelCumuloNimbus::getAltitudeRange(double *min_altitude, double *max_
*max_altitude = *min_altitude + 50.0 + 50.0 * layer->scaling;
}
double CloudModelCumuloNimbus::getDensity(const Vector3 &location) const {
double CloudModelCumuloNimbus::getDensity(const Vector3 &location, double) const {
double val;
double min_altitude, max_altitude;
double noise_scaling = 60.0 * layer->scaling;

View file

@ -16,7 +16,7 @@ class CloudModelCumuloNimbus : public BaseCloudsModel {
virtual void update() override;
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
virtual double getDensity(const Vector3 &location) const override;
virtual double getDensity(const Vector3 &location, double precision) const override;
private:
NoiseGenerator *noise;

View file

@ -37,7 +37,7 @@ void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max
*max_altitude = *min_altitude + 11.0 * layer->scaling;
}
double CloudModelStratoCumulus::getDensity(const Vector3 &location) const {
double CloudModelStratoCumulus::getDensity(const Vector3 &location, double precision) const {
double val;
double min_altitude, max_altitude;
double noise_scaling = 30.0 * layer->scaling;
@ -55,7 +55,7 @@ double CloudModelStratoCumulus::getDensity(const Vector3 &location) const {
// layer->scaling);
double coverage = layer->coverage;
val = 0.5 * noise->get3DTotal(x, y, z);
val = 0.5 * noise->get3DDetail(x, y, z, precision);
return val - 0.9 + coverage;
}
}

View file

@ -16,7 +16,7 @@ class CloudModelStratoCumulus : public BaseCloudsModel {
virtual void update() override;
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
virtual double getDensity(const Vector3 &location) const override;
virtual double getDensity(const Vector3 &location, double precision) const override;
private:
NoiseGenerator *noise;

View file

@ -11,3 +11,21 @@ TEST(Maths, modInRange) {
EXPECT_DOUBLE_EQ(5.2831853071795862, Maths::modInRange(-1.0, 0, Maths::TWOPI));
EXPECT_DOUBLE_EQ(-1.183185307179586, Maths::modInRange(5.1, -Maths::PI, Maths::PI));
}
TEST(Maths, zeroPoint) {
EXPECT_DOUBLE_EQ(0.5, Maths::zeroPoint(1.0, 1.0, -1.0));
EXPECT_DOUBLE_EQ(4.0, Maths::zeroPoint(2.0, 1.0, 0.5));
EXPECT_DOUBLE_EQ(-1.5, Maths::zeroPoint(1.5, -1.0, -2.0));
EXPECT_DOUBLE_EQ(0.0, Maths::zeroPoint(0.0, 1.0, 1.0));
}
TEST(Maths, smoothstep) {
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, -1.0));
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, 1.0));
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, 2.0));
EXPECT_DOUBLE_EQ(0.07407407407407407, Maths::smoothstep(2.0, 5.0, 2.5));
EXPECT_DOUBLE_EQ(0.25925925925925924, Maths::smoothstep(2.0, 5.0, 3.0));
EXPECT_DOUBLE_EQ(0.5, Maths::smoothstep(2.0, 5.0, 3.5));
EXPECT_DOUBLE_EQ(1.0, Maths::smoothstep(2.0, 5.0, 5.0));
EXPECT_DOUBLE_EQ(1.0, Maths::smoothstep(2.0, 5.0, 10.0));
}