Refactored cloud renderer (currently not working correctly)

This commit is contained in:
Michaël Lemaire 2013-12-01 19:24:53 +01:00
parent 7fecdba313
commit ff27afe675
30 changed files with 679 additions and 1045 deletions

View file

@ -4,7 +4,6 @@
#include "desktop_global.h" #include "desktop_global.h"
#include "baseformlayer.h" #include "baseformlayer.h"
#include "clouds/public.h"
class QWidget; class QWidget;
class FormClouds : public BaseFormLayer class FormClouds : public BaseFormLayer

View file

@ -7,7 +7,6 @@
#include "tools.h" #include "tools.h"
#include "render.h" #include "render.h"
#include "atmosphere/public.h" #include "atmosphere/public.h"
#include "clouds/public.h"
#include "terrain/public.h" #include "terrain/public.h"
#include "water/public.h" #include "water/public.h"
#include "RenderingScenery.h" #include "RenderingScenery.h"

View file

@ -1,11 +1,11 @@
#include "CloudsAspectPreviewRenderer.h" #include "CloudsAspectPreviewRenderer.h"
#include "clouds/public.h"
#include "atmosphere/public.h" #include "atmosphere/public.h"
#include "BasePreview.h" #include "BasePreview.h"
#include "Scenery.h" #include "Scenery.h"
#include "CloudsDefinition.h" #include "CloudsDefinition.h"
#include "CloudLayerDefinition.h" #include "CloudLayerDefinition.h"
#include "CloudsRenderer.h"
static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int) static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int)
{ {
@ -61,7 +61,6 @@ CloudsAspectPreviewRenderer::CloudsAspectPreviewRenderer(CloudLayerDefinition* l
CloudsDefinition* clouds = getScenery()->getClouds(); CloudsDefinition* clouds = getScenery()->getClouds();
clouds->clear(); clouds->clear();
clouds->addLayer(); clouds->addLayer();
CloudsRendererClass.bind(this, clouds);
render_quality = 6; render_quality = 6;
} }
@ -82,7 +81,7 @@ void CloudsAspectPreviewRenderer::updateEvent()
prepare(); prepare();
clouds->getLayerDensity = _getDensity; //clouds->getLayerDensity = _getDensity;
atmosphere->getLightingStatus = _getLightingStatus; atmosphere->getLightingStatus = _getLightingStatus;
atmosphere->applyAerialPerspective = _fakeApplyAerialPerspective; atmosphere->applyAerialPerspective = _fakeApplyAerialPerspective;
} }
@ -100,5 +99,5 @@ Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double)
end.z = start.z; end.z = start.z;
end.y = -start.y; end.y = -start.y;
return clouds->getColor(this, COLOR_BLUE, start, end); return getCloudsRenderer()->getColor(start, end, COLOR_BLUE);
} }

View file

@ -1,10 +1,10 @@
#include "CloudsCoveragePreviewRenderer.h" #include "CloudsCoveragePreviewRenderer.h"
#include "clouds/public.h"
#include "BasePreview.h" #include "BasePreview.h"
#include "Scenery.h" #include "Scenery.h"
#include "CloudsDefinition.h" #include "CloudsDefinition.h"
#include "CloudLayerDefinition.h" #include "CloudLayerDefinition.h"
#include "CloudsRenderer.h"
Color _fakeApplyLightingToSurface(Renderer*, Vector3, Vector3, SurfaceMaterial*) Color _fakeApplyLightingToSurface(Renderer*, Vector3, Vector3, SurfaceMaterial*)
{ {
@ -19,7 +19,6 @@ CloudsCoveragePreviewRenderer::CloudsCoveragePreviewRenderer(CloudLayerDefinitio
CloudsDefinition* clouds = getScenery()->getClouds(); CloudsDefinition* clouds = getScenery()->getClouds();
clouds->clear(); clouds->clear();
clouds->addLayer(); clouds->addLayer();
CloudsRendererClass.bind(this, clouds);
} }
void CloudsCoveragePreviewRenderer::bindEvent(BasePreview* preview) void CloudsCoveragePreviewRenderer::bindEvent(BasePreview* preview)
@ -49,7 +48,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali
look.z = 1.0; look.z = 1.0;
look = look.normalize(); look = look.normalize();
return clouds->getColor(this, COLOR_BLUE, eye, eye.add(look.scale(1000.0))); return getCloudsRenderer()->getColor(eye, eye.add(look.scale(1000.0)), COLOR_BLUE);
} }
else else
{ {
@ -60,7 +59,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali
start.y = 1000.0; start.y = 1000.0;
end.y = -1000.0; end.y = -1000.0;
return clouds->getColor(this, COLOR_BLUE, start, end); return getCloudsRenderer()->getColor(start, end, COLOR_BLUE);
} }
} }

View file

@ -0,0 +1,80 @@
#include "BaseCloudLayerRenderer.h"
#include "CloudLayerDefinition.h"
BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer* parent):
parent(parent)
{
}
BaseCloudLayerRenderer::~BaseCloudLayerRenderer()
{
}
double BaseCloudLayerRenderer::getDensity(CloudLayerDefinition *, const Vector3 &)
{
return 0.0;
}
Color BaseCloudLayerRenderer::getColor(CloudLayerDefinition *, const Vector3 &, const Vector3 &)
{
return COLOR_TRANSPARENT;
}
bool BaseCloudLayerRenderer::alterLight(CloudLayerDefinition *, LightDefinition *, const Vector3 &, const Vector3 &)
{
return false;
}
bool BaseCloudLayerRenderer::optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end)
{
Vector3 diff;
if (start->y > layer->lower_altitude + layer->thickness)
{
if (end->y >= layer->lower_altitude + layer->thickness)
{
return false;
}
else
{
diff = v3Sub(*end, *start);
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y));
if (end->y < layer->lower_altitude)
{
*end = v3Add(*end, v3Scale(diff, (layer->lower_altitude - end->y) / diff.y));
}
}
}
else if (start->y < layer->lower_altitude)
{
if (end->y <= layer->lower_altitude)
{
return false;
}
else
{
diff = v3Sub(*end, *start);
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y));
if (end->y >= layer->lower_altitude + layer->thickness)
{
*end = v3Add(*end, v3Scale(diff, (layer->lower_altitude + layer->thickness - end->y) / diff.y));
}
}
}
else /* start is inside layer */
{
diff = v3Sub(*end, *start);
if (end->y > layer->lower_altitude + layer->thickness)
{
*end = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y));
}
else if (end->y < layer->lower_altitude)
{
*end = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y));
}
}
return true;
}

View file

@ -0,0 +1,30 @@
#ifndef BASECLOUDLAYERRENDERER_H
#define BASECLOUDLAYERRENDERER_H
#include "software_global.h"
#include "tools/lighting.h"
namespace paysages {
namespace software {
class BaseCloudLayerRenderer
{
public:
BaseCloudLayerRenderer(SoftwareRenderer* parent);
virtual ~BaseCloudLayerRenderer();
virtual bool optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end);
virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location);
virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location);
virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location);
protected:
SoftwareRenderer* parent;
};
}
}
#endif // BASECLOUDLAYERRENDERER_H

View file

@ -0,0 +1,305 @@
#include "CloudBasicLayerRenderer.h"
#include "CloudLayerDefinition.h"
#include "SoftwareRenderer.h"
#include "NoiseGenerator.h"
#include "Curve.h"
#include "AtmosphereRenderer.h"
typedef struct
{
Vector3 start;
Vector3 end;
double length;
} CloudSegment;
CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer* parent):
BaseCloudLayerRenderer(parent)
{
}
static inline double _standardCoverageFunc(CloudLayerDefinition* layer, Vector3 position)
{
if (position.y < layer->lower_altitude || position.y > (layer->lower_altitude + layer->thickness))
{
return 0.0;
}
else
{
return layer->base_coverage * layer->_coverage_by_altitude->getValue((position.y - layer->lower_altitude) / layer->thickness);
}
}
static inline double _getDistanceToBorder(CloudLayerDefinition* layer, Vector3 position)
{
double val;
double minval, maxval;
layer->_shape_noise->getRange(&minval, &maxval);
val = 0.5 * layer->_shape_noise->get3DTotal(position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / maxval;
return (val - 0.5 + _standardCoverageFunc(layer, position)) * layer->shape_scaling;
}
static inline Vector3 _getNormal(CloudLayerDefinition* layer, Vector3 position, double detail)
{
Vector3 result = {0.0, 0.0, 0.0};
Vector3 dposition;
double val, dval;
val = _getDistanceToBorder(layer, position);
dposition.x = position.x + detail;
dposition.y = position.y;
dposition.z = position.z;
dval = val - _getDistanceToBorder(layer, dposition);
result.x += dval;
dposition.x = position.x - detail;
dval = val - _getDistanceToBorder(layer, dposition);
result.x -= dval;
dposition.x = position.x;
dposition.y = position.y + detail;
dval = val - _getDistanceToBorder(layer, dposition);
result.y += dval;
dposition.y = position.y - detail;
dval = val - _getDistanceToBorder(layer, dposition);
result.y -= dval;
dposition.y = position.y;
dposition.z = position.z + detail;
dval = val - _getDistanceToBorder(layer, dposition);
result.z += dval;
dposition.z = position.z - detail;
dval = val - _getDistanceToBorder(layer, dposition);
result.z -= dval;
return v3Normalize(result);
}
/**
* Go through the cloud layer to find segments (parts of the lookup that are inside the cloud).
*
* @param definition The cloud layer
* @param renderer The renderer environment
* @param start Start position of the lookup (already optimized)
* @param direction Normalized direction of the lookup
* @param detail Level of noise detail required
* @param max_segments Maximum number of segments to collect
* @param max_inside_length Maximum length to spend inside the cloud
* @param max_total_length Maximum lookup length
* @param inside_length Resulting length inside cloud (sum of all segments length)
* @param total_length Resulting lookup length
* @param out_segments Allocated space to fill found segments
* @return Number of segments found
*/
static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 start, Vector3 direction, double, int max_segments, double max_inside_length, double max_total_length, double* inside_length, double* total_length, CloudSegment* out_segments)
{
int inside, segment_count;
double current_total_length, current_inside_length;
double step_length, segment_length, remaining_length;
double noise_distance, last_noise_distance;
Vector3 walker, step, segment_start;
double render_precision;
if (max_segments <= 0)
{
return 0;
}
render_precision = 15.2 - 1.5 * (double)renderer->render_quality;
render_precision = render_precision * definition->shape_scaling / 50.0;
if (render_precision > max_total_length / 10.0)
{
render_precision = max_total_length / 10.0;
}
else if (render_precision < max_total_length / 2000.0)
{
render_precision = max_total_length / 2000.0;
}
segment_count = 0;
current_total_length = 0.0;
current_inside_length = 0.0;
segment_length = 0.0;
walker = start;
noise_distance = _getDistanceToBorder(definition, start) * render_precision;
inside = (noise_distance > 0.0) ? 1 : 0;
step = v3Scale(direction, render_precision);
do
{
walker = v3Add(walker, step);
step_length = v3Norm(step);
last_noise_distance = noise_distance;
noise_distance = _getDistanceToBorder(definition, walker) * render_precision;
current_total_length += step_length;
if (noise_distance > 0.0)
{
if (inside)
{
// inside the cloud
segment_length += step_length;
current_inside_length += step_length;
step = v3Scale(direction, (noise_distance < render_precision) ? render_precision : noise_distance);
}
else
{
// entering the cloud
inside = 1;
segment_length = step_length * noise_distance / (noise_distance - last_noise_distance);
segment_start = v3Add(walker, v3Scale(direction, -segment_length));
current_inside_length += segment_length;
step = v3Scale(direction, render_precision);
}
}
else
{
if (inside)
{
// exiting the cloud
remaining_length = step_length * last_noise_distance / (last_noise_distance - noise_distance);
segment_length += remaining_length;
current_inside_length += remaining_length;
out_segments->start = segment_start;
out_segments->end = v3Add(walker, v3Scale(direction, remaining_length - step_length));
out_segments->length = segment_length;
out_segments++;
if (++segment_count >= max_segments)
{
break;
}
inside = 0;
step = v3Scale(direction, render_precision);
}
else
{
// searching for a cloud
step = v3Scale(direction, (noise_distance > -render_precision) ? render_precision : -noise_distance);
}
}
} while (inside || (walker.y >= definition->lower_altitude - 0.001 && walker.y <= (definition->lower_altitude + definition->thickness) + 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length));
*total_length = current_total_length;
*inside_length = current_inside_length;
return segment_count;
}
static Color _applyLayerLighting(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 position, double)
{
Vector3 normal;
Color col1, col2;
normal = _getNormal(definition, position, 3.0);
if (renderer->render_quality > 5)
{
normal = v3Add(normal, _getNormal(definition, position, 2.0));
normal = v3Add(normal, _getNormal(definition, position, 1.0));
}
if (renderer->render_quality > 5)
{
normal = v3Add(normal, _getNormal(definition, position, 0.5));
}
normal = v3Scale(v3Normalize(normal), definition->hardness);
// TODO Compute light filter only once
col1 = renderer->applyLightingToSurface(renderer, position, normal, definition->material);
col2 = renderer->applyLightingToSurface(renderer, position, v3Scale(normal, -1.0), definition->material);
col1.r = (col1.r + col2.r) / 2.0;
col1.g = (col1.g + col2.g) / 2.0;
col1.b = (col1.b + col2.b) / 2.0;
col1.a = (col1.a + col2.a) / 2.0;
return col1;
}
double CloudBasicLayerRenderer::getDensity(CloudLayerDefinition* layer, const Vector3 &location)
{
return 0.0;
}
Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location)
{
int i, segment_count;
double max_length, detail, total_length, inside_length;
Vector3 start, end, direction;
Color result, col;
CloudSegment segments[20];
start = eye;
end = location;
if (!optimizeSearchLimits(layer, &start, &end))
{
return COLOR_TRANSPARENT;
}
direction = end.sub(start);
max_length = direction.getNorm();
direction = direction.normalize();
result = COLOR_TRANSPARENT;
detail = parent->getPrecision(parent, start) / layer->shape_scaling;
segment_count = _findSegments(layer, parent, start, direction, detail, 20, layer->transparencydepth, max_length, &inside_length, &total_length, segments);
for (i = segment_count - 1; i >= 0; i--)
{
col = _applyLayerLighting(layer, parent, segments[i].start, detail);
col.a = (segments[i].length >= layer->transparencydepth) ? 1.0 : (segments[i].length / layer->transparencydepth);
colorMask(&result, &col);
}
if (inside_length >= layer->transparencydepth)
{
result.a = 1.0;
}
double a = result.a;
result = parent->getAtmosphereRenderer()->applyAerialPerspective(start, result).final;
result.a = a;
return result;
}
bool CloudBasicLayerRenderer::alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &, const Vector3 &location)
{
Vector3 start, end;
double inside_depth, total_depth, factor;
CloudSegment segments[20];
start = location;
end = location.add(light->direction.scale(10000.0));
if (not optimizeSearchLimits(layer, &start, &end))
{
return false;
}
_findSegments(layer, parent, start, light->direction, 0.1, 20, layer->lighttraversal, end.sub(start).getNorm(), &inside_depth, &total_depth, segments);
if (layer->lighttraversal < 0.0001)
{
factor = 0.0;
}
else
{
factor = inside_depth / layer->lighttraversal;
if (factor > 1.0)
{
factor = 1.0;
}
}
factor = 1.0 - (1.0 - layer->minimumlight) * factor;
light->color.r *= factor;
light->color.g *= factor;
light->color.b *= factor;
return true;
}

View file

@ -0,0 +1,26 @@
#ifndef CLOUDBASICLAYERRENDERER_H
#define CLOUDBASICLAYERRENDERER_H
#include "software_global.h"
#include "BaseCloudLayerRenderer.h"
#include "tools/lighting.h"
namespace paysages {
namespace software {
class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer: public BaseCloudLayerRenderer
{
public:
CloudBasicLayerRenderer(SoftwareRenderer* parent);
virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location) override;
virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) override;
virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override;
};
}
}
#endif // CLOUDBASICLAYERRENDERER_H

View file

@ -0,0 +1,81 @@
#include "CloudsRenderer.h"
#include "SoftwareRenderer.h"
#include "Scenery.h"
#include "CloudsDefinition.h"
#include "BaseCloudLayerRenderer.h"
#include "CloudBasicLayerRenderer.h"
CloudsRenderer::CloudsRenderer(SoftwareRenderer* parent):
parent(parent)
{
fake_renderer = new BaseCloudLayerRenderer(parent);
}
CloudsRenderer::~CloudsRenderer()
{
for (auto renderer : layer_renderers)
{
delete renderer;
}
delete fake_renderer;
}
void CloudsRenderer::update()
{
for (auto renderer : layer_renderers)
{
delete renderer;
}
layer_renderers.clear();
CloudsDefinition* clouds = parent->getScenery()->getClouds();
int n = clouds->count();
for (int i = 0; i < n; i++)
{
layer_renderers.push_back(new CloudBasicLayerRenderer(parent));
}
}
BaseCloudLayerRenderer* CloudsRenderer::getLayerRenderer(unsigned int layer)
{
if (layer < layer_renderers.size())
{
return layer_renderers[layer];
}
else
{
return fake_renderer;
}
}
Color CloudsRenderer::getColor(const Vector3 &eye, const Vector3 &location, const Color &base)
{
CloudsDefinition* definition = parent->getScenery()->getClouds();
int n = definition->count();
if (n < 1)
{
return base;
}
/* TODO Iter layers in sorted order */
Color cumul = base;
for (int i = 0; i < n; i++)
{
CloudLayerDefinition* layer = definition->getCloudLayer(i);
BaseCloudLayerRenderer* layer_renderer = getLayerRenderer(i);
Color layer_color = layer_renderer->getColor(layer, eye, location);
colorMask(&cumul, &layer_color);
}
return cumul;
}
bool CloudsRenderer::alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location)
{
return false;
}

View file

@ -0,0 +1,52 @@
#ifndef CLOUDSRENDERER_H
#define CLOUDSRENDERER_H
#include "software_global.h"
#include "tools/lighting.h"
namespace paysages {
namespace software {
/*!
* \brief Software renderer of a group of cloud layers.
*/
class SOFTWARESHARED_EXPORT CloudsRenderer
{
public:
CloudsRenderer(SoftwareRenderer* parent);
virtual ~CloudsRenderer();
/*!
* Update the renderer with the bound scenery.
*/
void update();
/*!
* Get the layer renderer for a given layer.
*
* The returned renderer is managed by this object and should not be deleted.
*/
virtual BaseCloudLayerRenderer* getLayerRenderer(unsigned int layer);
/*!
* Get the composited color, as applied on a base color and location.
*/
virtual Color getColor(const Vector3 &eye, const Vector3 &location, const Color &base);
/*!
* Alter a light, as if passed through all layers.
*
* Return true if the light was altered.
*/
virtual bool alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location);
private:
SoftwareRenderer* parent;
std::vector<BaseCloudLayerRenderer*> layer_renderers;
BaseCloudLayerRenderer* fake_renderer;
};
}
}
#endif // CLOUDSRENDERER_H

View file

@ -1,12 +1,19 @@
#include "public.h" #include "SkyRasterizer.h"
#include "private.h"
#include <math.h> #include "Vector3.h"
#include <stdlib.h> #include "Color.h"
#include "../renderer.h" #include "SoftwareRenderer.h"
#include "clouds/public.h" #include "AtmosphereRenderer.h"
#include "CloudsRenderer.h"
static Color _postProcessFragment(Renderer* renderer, Vector3 location, void*) #define SPHERE_SIZE 20000.0
SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer):
renderer(renderer)
{
}
static Color _postProcessFragment(SoftwareRenderer* renderer, Vector3 location, void*)
{ {
Vector3 camera_location, direction; Vector3 camera_location, direction;
Color result; Color result;
@ -16,12 +23,12 @@ static Color _postProcessFragment(Renderer* renderer, Vector3 location, void*)
/* TODO Don't compute result->color if it's fully covered by clouds */ /* TODO Don't compute result->color if it's fully covered by clouds */
result = renderer->atmosphere->getSkyColor(renderer, v3Normalize(direction)).final; result = renderer->atmosphere->getSkyColor(renderer, v3Normalize(direction)).final;
result = renderer->clouds->getColor(renderer, result, camera_location, v3Add(camera_location, v3Scale(direction, 10.0))); result = renderer->getCloudsRenderer()->getColor(camera_location, v3Add(camera_location, v3Scale(direction, 10.0)), result);
return result; return result;
} }
void atmosphereRenderSkydome(Renderer* renderer) void SkyRasterizer::rasterize()
{ {
int res_i, res_j; int res_i, res_j;
int i, j; int i, j;
@ -71,7 +78,7 @@ void atmosphereRenderSkydome(Renderer* renderer)
vertex4 = v3Add(camera_location, direction); vertex4 = v3Add(camera_location, direction);
/* TODO Triangles at poles */ /* TODO Triangles at poles */
renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, _postProcessFragment, NULL); renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, (f_RenderFragmentCallback)_postProcessFragment, NULL);
} }
} }
} }

View file

@ -0,0 +1,22 @@
#ifndef SKYRASTERIZER_H
#define SKYRASTERIZER_H
#include "software_global.h"
namespace paysages {
namespace software {
class SOFTWARESHARED_EXPORT SkyRasterizer
{
public:
SkyRasterizer(SoftwareRenderer* renderer);
void rasterize();
private:
SoftwareRenderer* renderer;
};
}
}
#endif // SKYRASTERIZER_H

View file

@ -5,12 +5,14 @@
#include "FluidMediumManager.h" #include "FluidMediumManager.h"
#include "AtmosphereRenderer.h" #include "AtmosphereRenderer.h"
#include "AtmosphereDefinition.h" #include "AtmosphereDefinition.h"
#include "CloudsRenderer.h"
#include "SkyRasterizer.h"
// Legacy compatibility // Legacy compatibility
#include "renderer.h" #include "renderer.h"
#include "terrain/public.h" #include "terrain/public.h"
#include "clouds/public.h" #include "terrain/ter_raster.h"
#include "textures/public.h" #include "textures/public.h"
#include "water/public.h" #include "water/public.h"
static AtmosphereResult _legacyApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base) static AtmosphereResult _legacyApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base)
@ -29,8 +31,9 @@ static Vector3 _legacyGetSunDirection(Renderer* renderer)
{ {
return ((SoftwareRenderer*)renderer)->getAtmosphereRenderer()->getSunDirection(); return ((SoftwareRenderer*)renderer)->getAtmosphereRenderer()->getSunDirection();
} }
static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector3 direction, int, int, int, int) static RayCastingResult _rayWalking(Renderer* renderer_, Vector3 location, Vector3 direction, int, int, int, int)
{ {
SoftwareRenderer* renderer = (SoftwareRenderer*)renderer_;
RayCastingResult result; RayCastingResult result;
Color sky_color; Color sky_color;
@ -41,7 +44,7 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector
result.hit = 1; result.hit = 1;
result.hit_location = v3Add(location, v3Scale(direction, 1000.0)); result.hit_location = v3Add(location, v3Scale(direction, 1000.0));
result.hit_color = renderer->clouds->getColor(renderer, sky_color, location, result.hit_location); result.hit_color = renderer->getCloudsRenderer()->getColor(location, result.hit_location, sky_color);
} }
return result; return result;
@ -60,6 +63,7 @@ static double _getPrecision(Renderer* renderer, Vector3 location)
SoftwareRenderer::SoftwareRenderer(Scenery* scenery) SoftwareRenderer::SoftwareRenderer(Scenery* scenery)
{ {
atmosphere_renderer = new BaseAtmosphereRenderer(this); atmosphere_renderer = new BaseAtmosphereRenderer(this);
clouds_renderer = new CloudsRenderer(this);
fluid_medium = new FluidMediumManager(this); fluid_medium = new FluidMediumManager(this);
@ -78,6 +82,7 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery)
SoftwareRenderer::~SoftwareRenderer() SoftwareRenderer::~SoftwareRenderer()
{ {
delete atmosphere_renderer; delete atmosphere_renderer;
delete clouds_renderer;
delete fluid_medium; delete fluid_medium;
@ -103,6 +108,10 @@ void SoftwareRenderer::prepare()
delete atmosphere_renderer; delete atmosphere_renderer;
atmosphere_renderer = new SoftwareBrunetonAtmosphereRenderer(this); atmosphere_renderer = new SoftwareBrunetonAtmosphereRenderer(this);
delete clouds_renderer;
clouds_renderer = new CloudsRenderer(this);
clouds_renderer->update();
// Setup transitional renderers (for C-legacy subsystems) // Setup transitional renderers (for C-legacy subsystems)
rayWalking = _rayWalking; rayWalking = _rayWalking;
getPrecision = _getPrecision; getPrecision = _getPrecision;
@ -116,7 +125,6 @@ void SoftwareRenderer::prepare()
scenery->getCamera()->copy(render_camera); scenery->getCamera()->copy(render_camera);
TerrainRendererClass.bind(this, scenery->getTerrain()); TerrainRendererClass.bind(this, scenery->getTerrain());
TexturesRendererClass.bind(this, scenery->getTextures()); TexturesRendererClass.bind(this, scenery->getTextures());
CloudsRendererClass.bind(this, scenery->getClouds());
WaterRendererClass.bind(this, scenery->getWater()); WaterRendererClass.bind(this, scenery->getWater());
// Prepare global tools // Prepare global tools
@ -124,8 +132,21 @@ void SoftwareRenderer::prepare()
//fluid_medium->registerMedium(water_renderer); //fluid_medium->registerMedium(water_renderer);
} }
/*Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color) void SoftwareRenderer::rasterize()
{ {
Vector3 eye = cameraGetLocation(scenery->getCamera()); terrainRenderSurface(this);
return fluid_medium->applyTraversal(eye, location, color); waterRenderSurface(this);
}*/
SkyRasterizer sky(this);
sky.rasterize();
}
Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color)
{
color = atmosphere->applyAerialPerspective(this, location, color).final;
color = clouds_renderer->getColor(getCameraLocation(this, location), location, color);
return color;
/*Vector3 eye = cameraGetLocation(scenery->getCamera());
return fluid_medium->applyTraversal(eye, location, color);*/
}

View file

@ -33,17 +33,26 @@ public:
*/ */
virtual void prepare() override; virtual void prepare() override;
/*!
* \brief Start the rasterization process.
*/
virtual void rasterize() override;
inline Scenery* getScenery() const {return scenery;} inline Scenery* getScenery() const {return scenery;}
inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;} inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;}
inline CloudsRenderer* getCloudsRenderer() const {return clouds_renderer;}
inline FluidMediumManager* getFluidMediumManager() const {return fluid_medium;} inline FluidMediumManager* getFluidMediumManager() const {return fluid_medium;}
//virtual Color applyMediumTraversal(Vector3 location, Color color) override; virtual Color applyMediumTraversal(Vector3 location, Color color) override;
private: private:
Scenery* scenery; Scenery* scenery;
bool own_scenery; bool own_scenery;
FluidMediumManager* fluid_medium; FluidMediumManager* fluid_medium;
BaseAtmosphereRenderer* atmosphere_renderer; BaseAtmosphereRenderer* atmosphere_renderer;
CloudsRenderer* clouds_renderer;
}; };
} }

View file

@ -16,13 +16,21 @@ include(../../common.pri)
SOURCES += SoftwareRenderer.cpp \ SOURCES += SoftwareRenderer.cpp \
FluidMediumInterface.cpp \ FluidMediumInterface.cpp \
FluidMediumManager.cpp \ FluidMediumManager.cpp \
AtmosphereRenderer.cpp AtmosphereRenderer.cpp \
CloudsRenderer.cpp \
BaseCloudLayerRenderer.cpp \
SkyRasterizer.cpp \
CloudBasicLayerRenderer.cpp
HEADERS += SoftwareRenderer.h\ HEADERS += SoftwareRenderer.h\
software_global.h \ software_global.h \
FluidMediumInterface.h \ FluidMediumInterface.h \
FluidMediumManager.h \ FluidMediumManager.h \
AtmosphereRenderer.h AtmosphereRenderer.h \
CloudsRenderer.h \
BaseCloudLayerRenderer.h \
SkyRasterizer.h \
CloudBasicLayerRenderer.h
unix:!symbian { unix:!symbian {
maemo5 { maemo5 {

View file

@ -21,6 +21,9 @@ namespace software {
class BaseAtmosphereRenderer; class BaseAtmosphereRenderer;
class SoftwareBrunetonAtmosphereRenderer; class SoftwareBrunetonAtmosphereRenderer;
class CloudsRenderer;
class BaseCloudLayerRenderer;
} }
} }

View file

@ -55,13 +55,3 @@ void RenderingScenery::bindToRenderer(Renderer* renderer)
renderer->setScenery(this); renderer->setScenery(this);
renderer->prepare(); renderer->prepare();
} }
// Transitional C-API
void sceneryRenderFirstPass(Renderer* renderer)
{
terrainRenderSurface(renderer);
waterRenderSurface(renderer);
atmosphereRenderSkydome(renderer);
}

View file

@ -34,8 +34,4 @@ private:
void* _custom_data; void* _custom_data;
}; };
// Transitional C-API
RENDERINGSHARED_EXPORT void sceneryRenderFirstPass(Renderer* renderer);
#endif // SCENERY_H #endif // SCENERY_H

View file

@ -38,8 +38,6 @@ public:
RENDERINGSHARED_EXPORT extern StandardRenderer AtmosphereRendererClass; RENDERINGSHARED_EXPORT extern StandardRenderer AtmosphereRendererClass;
RENDERINGSHARED_EXPORT void atmosphereRenderSkydome(Renderer* renderer);
RENDERINGSHARED_EXPORT void atmosphereInitResult(AtmosphereResult* result); RENDERINGSHARED_EXPORT void atmosphereInitResult(AtmosphereResult* result);
RENDERINGSHARED_EXPORT void atmosphereUpdateResult(AtmosphereResult* result); RENDERINGSHARED_EXPORT void atmosphereUpdateResult(AtmosphereResult* result);

View file

@ -1,103 +0,0 @@
#include "clo_density.h"
#include "NoiseGenerator.h"
#include "CloudLayerDefinition.h"
#include "Curve.h"
double cloudsGetLayerCoverage(CloudLayerDefinition* layer, Vector3 location)
{
if (layer->base_coverage <= 0.0)
{
return 0.0;
}
else
{
double coverage = 0.5 + layer->_coverage_noise->get2DTotal(location.x / layer->shape_scaling, location.z / layer->shape_scaling);
coverage -= (1.0 - layer->base_coverage);
coverage *= layer->_coverage_by_altitude->getValue((location.y - layer->lower_altitude) / layer->thickness);
if (coverage < 0.0)
{
return 0.0;
}
else if (coverage >= 1.0)
{
return 1.0;
}
else
{
return coverage;
}
}
}
double cloudsGetLayerDensity(CloudLayerDefinition* layer, Vector3 location, double coverage)
{
if (coverage <= 0.0)
{
return 0.0;
}
else if (coverage >= 1.0)
{
return 1.0;
}
else
{
double density = layer->_shape_noise->get3DTotal(location.x / layer->shape_scaling, location.y / layer->shape_scaling, location.z / layer->shape_scaling);
density -= (0.5 - coverage);
return (density <= 0.0) ? 0.0 : density;
}
}
double cloudsGetEdgeDensity(CloudLayerDefinition* layer, Vector3 location, double layer_density)
{
if (layer_density <= 0.0)
{
return 0.0;
}
else if (layer_density >= 1.0)
{
return 1.0;
}
else
{
double density = layer->_edge_noise->get3DTotal(location.x / layer->edge_scaling, location.y / layer->edge_scaling, location.z / layer->edge_scaling);
density -= (0.5 - layer_density);
return (density <= 0.0) ? 0.0 : density;
}
}
static double _fakeGetDensity(Renderer*, CloudLayerDefinition*, Vector3)
{
return 0.0;
}
static double _fakeGetEdgeDensity(Renderer*, CloudLayerDefinition*, Vector3, double)
{
return 0.0;
}
void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer)
{
renderer->getLayerDensity = _fakeGetDensity;
renderer->getEdgeDensity = _fakeGetEdgeDensity;
}
static double _realGetDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location)
{
double coverage = cloudsGetLayerCoverage(layer, location);
return cloudsGetLayerDensity(layer, location, coverage);
}
static double _realGetEdgeDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location, double layer_density)
{
return cloudsGetEdgeDensity(layer, location, layer_density);
}
void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer)
{
renderer->getLayerDensity = _realGetDensity;
renderer->getEdgeDensity = _realGetEdgeDensity;
}

View file

@ -1,41 +0,0 @@
#ifndef _PAYSAGES_CLOUDS_DENSITY_H_
#define _PAYSAGES_CLOUDS_DENSITY_H_
#include "public.h"
/**
* Coverage/density management in a cloud layer.
*/
/**
* Get the coverage of a cloud layer [0.0;1.0]
*
* 0.0 means no cloud is present.
* 1.0 means full layer.
*/
RENDERINGSHARED_EXPORT double cloudsGetLayerCoverage(CloudLayerDefinition* layer, Vector3 location);
/**
* Get the global density of a cloud layer at a given point [0.0;1.0].
*
* 0.0 means no cloud is present.
* 1.0 means full density (deep inside cloud).
*/
RENDERINGSHARED_EXPORT double cloudsGetLayerDensity(CloudLayerDefinition* layer, Vector3 location, double coverage);
/**
* Get the local density of a cloud layer at a given point inside an edge [0.0;1.0].
*/
RENDERINGSHARED_EXPORT double cloudsGetEdgeDensity(CloudLayerDefinition* layer, Vector3 location, double layer_density);
/*
* Bind fake density functions to a renderer.
*/
RENDERINGSHARED_EXPORT void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer);
/*
* Bind real density functions to a renderer.
*/
RENDERINGSHARED_EXPORT void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer);
#endif

View file

@ -1,278 +0,0 @@
#include "private.h"
#include <assert.h>
#include <stdlib.h>
#include "../renderer.h"
#include "clo_density.h"
#include "clo_walking.h"
#include "atmosphere/public.h"
#include "CloudsDefinition.h"
#include "CloudLayerDefinition.h"
/******************** Fake ********************/
static int _fakeAlterLight(Renderer*, LightDefinition*, Vector3)
{
return 0;
}
static Color _fakeGetColor(Renderer*, Color base, Vector3, Vector3)
{
return base;
}
/******************** Real ********************/
typedef struct
{
double light_power;
double out_scattering; /* Amount of light scattered away by heavy particles */
} AccumulatedLightData;
static void _walkerFilterCallback(CloudsWalker* walker)
{
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
Renderer* renderer = segment->renderer;
AccumulatedLightData* data = (AccumulatedLightData*)segment->data;
assert(data != NULL);
double density_integral;
if (segment->subdivided)
{
density_integral = segment->length * (segment->start.local_density + segment->end.local_density) / 2.0;
}
else
{
if (!segment->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0)
{
cloudsWalkerOrderRefine(walker, 1.0 / (double)renderer->render_quality);
return;
}
else if ((segment->start.global_density > 0.0 || segment->end.global_density > 0.0) && (segment->start.global_density < 1.0 || segment->end.global_density < 1.0))
{
cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 1);
return;
}
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
}
data->out_scattering += 0.3 * density_integral;
if (data->out_scattering > data->light_power)
{
cloudsWalkerOrderStop(walker);
}
}
static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location)
{
CloudsDefinition* definition = renderer->clouds->definition;
int i, n;
AccumulatedLightData data;
data.out_scattering = 0.0;
data.light_power = colorGetPower(&light->color);
/* TODO Iter layers in sorted order */
n = definition->count();
for (i = 0; i < n; i++)
{
CloudLayerDefinition* layer = definition->getCloudLayer(i);
Vector3 ostart, oend;
ostart = location;
oend = v3Add(location, v3Scale(light->direction, -10000.0));
if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
{
continue;
}
else
{
CloudsWalker* walker;
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
cloudsWalkerSetStepSize(walker, -1.0);
cloudsWalkerSetVoidSkipping(walker, 1);
cloudsStartWalking(walker, _walkerFilterCallback, &data);
cloudsDeleteWalker(walker);
}
}
double max_power = data.light_power - data.out_scattering;
if (max_power < 0.0)
{
light->color = COLOR_BLACK;
}
else
{
colorLimitPower(&light->color, max_power);
}
return data.out_scattering > 0.0;
}
typedef struct
{
double out_scattering; /* Amount of light scattered away by heavy particles */
Color in_scattering; /* Amount of light redirected toward the viewer */
int entry_found; /* 1 if a cloud entry has been found */
Vector3 entry; /* Point of entry in the clouds */
} AccumulatedMaterialData;
static inline void _applyOutScattering(Color* col, double out_scattering)
{
if (out_scattering >= 1.0)
{
col->r = col->g = col->b = 0.0;
}
else
{
col->r *= (1.0 - out_scattering);
col->g *= (1.0 - out_scattering);
col->b *= (1.0 - out_scattering);
}
}
static void _walkerMaterialCallback(CloudsWalker* walker)
{
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
AccumulatedMaterialData* data = (AccumulatedMaterialData*)segment->data;
Renderer* renderer = segment->renderer;
CloudLayerDefinition* layer = segment->layer;
assert(data != NULL);
double density_integral;
if (segment->subdivided)
{
density_integral = segment->length * (segment->start.local_density + segment->end.local_density) / 2.0;
}
else
{
if (!segment->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0)
{
cloudsWalkerOrderRefine(walker, 1.0 / (double)(renderer->render_quality * renderer->render_quality));
return;
}
else if ((segment->start.global_density > 0.0 || segment->end.global_density > 0.0) && (segment->start.global_density < 1.0 || segment->end.global_density < 1.0))
{
cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 3);
return;
}
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
}
if (density_integral > 0.0)
{
data->out_scattering += 0.3 * density_integral;
Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_ZERO, layer->material);
in_scattering.r *= density_integral * 5.0;
in_scattering.g *= density_integral * 5.0;
in_scattering.b *= density_integral * 5.0;
_applyOutScattering(&in_scattering, data->out_scattering);
data->in_scattering.r += in_scattering.r;
data->in_scattering.g += in_scattering.g;
data->in_scattering.b += in_scattering.b;
if (!data->entry_found)
{
data->entry_found = 1;
data->entry = segment->start.location;
}
}
}
static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end)
{
CloudsDefinition* definition = renderer->clouds->definition;
int i, n;
n = definition->count();
if (n < 1)
{
return base;
}
/* TODO Iter layers in sorted order */
for (i = 0; i < n; i++)
{
CloudLayerDefinition* layer = definition->getCloudLayer(i);
Vector3 ostart, oend;
ostart = start;
oend = end;
if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
{
continue;
}
else
{
CloudsWalker* walker;
AccumulatedMaterialData data;
data.out_scattering = 0.0;
data.in_scattering = COLOR_BLACK;
data.entry = ostart;
data.entry_found = 0;
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
cloudsWalkerSetStepSize(walker, -1.0);
cloudsWalkerSetVoidSkipping(walker, 1);
cloudsStartWalking(walker, _walkerMaterialCallback, &data);
cloudsDeleteWalker(walker);
/* Apply final out_scattering to base */
_applyOutScattering(&base, data.out_scattering);
/* Apply in_scattering */
base.r += data.in_scattering.r;
base.g += data.in_scattering.g;
base.b += data.in_scattering.b;
/* Apply aerial perspective approximation */
base = renderer->atmosphere->applyAerialPerspective(renderer, data.entry, base).final;
}
}
return base;
}
/******************** Renderer ********************/
static CloudsRenderer* _createRenderer()
{
CloudsRenderer* result;
result = new CloudsRenderer;
result->definition = new CloudsDefinition(NULL);
result->getColor = _fakeGetColor;
result->alterLight = (FuncLightingAlterLight)_fakeAlterLight;
cloudsBindFakeDensityToRenderer(result);
return result;
}
static void _deleteRenderer(CloudsRenderer* renderer)
{
delete renderer->definition;
delete renderer;
}
static void _bindRenderer(Renderer* renderer, CloudsDefinition* definition)
{
definition->copy(renderer->clouds->definition);
renderer->clouds->getColor = _getColor;
renderer->clouds->alterLight = (FuncLightingAlterLight)_alterLight;
cloudsBindRealDensityToRenderer(renderer->clouds);
lightingManagerRegisterFilter(renderer->lighting, (FuncLightingAlterLight)_alterLight, renderer);
}
StandardRenderer CloudsRendererClass = {
(FuncObjectCreate)_createRenderer,
(FuncObjectDelete)_deleteRenderer,
(FuncObjectBind)_bindRenderer
};

View file

@ -1,364 +0,0 @@
#include "clo_walking.h"
#include "../renderer.h"
#include "CloudLayerDefinition.h"
/**
* Control of the next walking order.
*/
typedef enum
{
CLOUD_WALKING_CONTINUE,
CLOUD_WALKING_STOP,
CLOUD_WALKING_REFINE,
CLOUD_WALKING_SUBDIVIDE
} CloudWalkingOrder;
/**
* Additional info for walking orders.
*/
typedef struct
{
CloudWalkingOrder order;
double precision;
int max_segments;
} CloudWalkingNextAction;
/*
* Private structure for the walker.
*/
struct CloudsWalker
{
Vector3 start;
Vector3 end;
Vector3 diff;
double cursor;
double max_length;
double step_size;
int skip_void;
int local_density;
int started;
CloudWalkerStepInfo last_segment;
int subdivision_current;
int subdivision_count;
CloudWalkerStepInfo subdivision_parent;
CloudWalkingNextAction next_action;
};
int cloudsOptimizeWalkingBounds(CloudLayerDefinition* layer, Vector3* start, Vector3* end)
{
Vector3 diff;
if (start->y > layer->lower_altitude + layer->thickness)
{
if (end->y >= layer->lower_altitude + layer->thickness)
{
return 0;
}
else
{
diff = v3Sub(*end, *start);
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y));
if (end->y < layer->lower_altitude)
{
*end = v3Add(*end, v3Scale(diff, (layer->lower_altitude - end->y) / diff.y));
}
}
}
else if (start->y < layer->lower_altitude)
{
if (end->y <= layer->lower_altitude)
{
return 0;
}
else
{
diff = v3Sub(*end, *start);
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y));
if (end->y >= layer->lower_altitude + layer->thickness)
{
*end = v3Add(*end, v3Scale(diff, (layer->lower_altitude + layer->thickness - end->y) / diff.y));
}
}
}
else /* start is inside layer */
{
diff = v3Sub(*end, *start);
if (end->y > layer->lower_altitude + layer->thickness)
{
*end = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y));
}
else if (end->y < layer->lower_altitude)
{
*end = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y));
}
}
return 1;
}
CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudLayerDefinition* layer, Vector3 start, Vector3 end)
{
CloudsWalker* result;
result = (CloudsWalker*)malloc(sizeof (CloudsWalker));
result->start = start;
result->end = end;
result->diff = v3Sub(end, start);
result->max_length = v3Norm(result->diff);
result->cursor = 0.0;
result->step_size = 1.0;
result->skip_void = 0;
result->local_density = -1;
result->started = 0;
result->subdivision_count = 0;
result->last_segment.renderer = renderer;
result->last_segment.layer = layer;
result->next_action.order = CLOUD_WALKING_CONTINUE;
return result;
}
void cloudsDeleteWalker(CloudsWalker* walker)
{
free(walker);
}
void cloudsWalkerSetStepSize(CloudsWalker* walker, double step)
{
if (step > 0.0)
{
walker->step_size = step;
}
else
{
/* TODO Automatic settings (using rendering quality and cloud feature size) */
walker->step_size = 5.0 / (double)walker->last_segment.renderer->render_quality;
}
}
void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled)
{
walker->local_density = enabled;
}
void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled)
{
walker->skip_void = enabled;
}
static void _getPoint(CloudsWalker* walker, double cursor, CloudWalkerPoint* out_point)
{
out_point->distance_from_start = cursor;
out_point->location = v3Add(walker->start, v3Scale(walker->diff, out_point->distance_from_start / walker->max_length));
Renderer* renderer = walker->last_segment.renderer;
CloudLayerDefinition* layer = walker->last_segment.layer;
out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
if (walker->local_density > 0 || (walker->local_density < 0 && walker->subdivision_count > 0))
{
out_point->local_density = renderer->clouds->getEdgeDensity(renderer, layer, out_point->location, out_point->global_density);
}
else
{
out_point->local_density = 0.0;
}
}
static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
{
CloudWalkerPoint middle;
_getPoint(walker, (start_cursor + end_cursor) / 2.0, &middle);
if (start_density == 0.0)
{
/* Looking for entry */
if (middle.distance_from_start - start_cursor < precision)
{
*result = middle;
}
else if (middle.global_density == 0.0)
{
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
}
else
{
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
}
}
else
{
/* Looking for exit */
if (end_cursor - middle.distance_from_start < precision)
{
*result = middle;
}
else if (middle.global_density == 0.0)
{
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
}
else
{
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
}
}
}
int cloudsWalkerPerformStep(CloudsWalker* walker)
{
int result = -1;
if (!walker->started)
{
_getPoint(walker, 0.0, &walker->last_segment.end);
walker->started = 1;
}
while (result < 0)
{
if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
{
walker->next_action.order = CLOUD_WALKING_STOP;
result = 0;
}
else if (walker->subdivision_count > 0)
{
if (walker->subdivision_current >= walker->subdivision_count)
{
/* Exit subdivision */
walker->subdivision_count = 0;
walker->last_segment = walker->subdivision_parent;
walker->next_action.order = CLOUD_WALKING_CONTINUE;
walker->cursor = walker->subdivision_parent.end.distance_from_start;
/* Recursive call to progress */
result = cloudsWalkerPerformStep(walker);
}
else
{
/* Continue subdivision */
walker->last_segment.start = walker->last_segment.end;
walker->cursor += walker->subdivision_parent.length / (double)walker->subdivision_count;
_getPoint(walker, walker->cursor, &walker->last_segment.end);
walker->last_segment.length = walker->subdivision_parent.length / (double)walker->subdivision_count;
walker->last_segment.refined = 0;
walker->last_segment.subdivided = walker->subdivision_count;
walker->subdivision_current++;
result = 1;
}
}
else if (walker->next_action.order == CLOUD_WALKING_CONTINUE)
{
/* TODO Limit to lookup end */
walker->last_segment.start = walker->last_segment.end;
walker->cursor += walker->step_size;
_getPoint(walker, walker->cursor, &walker->last_segment.end);
walker->last_segment.length = walker->step_size;
walker->last_segment.refined = 0;
walker->last_segment.subdivided = 0;
result = 1;
}
else if (walker->next_action.order == CLOUD_WALKING_REFINE)
{
/* Refine segment with dichotomy */
_refineSegment(walker,
walker->last_segment.start.distance_from_start,
walker->last_segment.start.global_density,
walker->last_segment.end.distance_from_start,
walker->last_segment.end.global_density,
walker->next_action.precision,
(walker->last_segment.start.global_density == 0.0) ? (&walker->last_segment.start) : (&walker->last_segment.end));
walker->last_segment.length = walker->last_segment.end.distance_from_start - walker->last_segment.start.distance_from_start;
walker->last_segment.refined = 1;
walker->last_segment.subdivided = 0;
walker->next_action.order = CLOUD_WALKING_CONTINUE;
result = 1;
}
else if (walker->next_action.order == CLOUD_WALKING_SUBDIVIDE)
{
/* Starting subdivision */
walker->subdivision_count = walker->next_action.max_segments;
walker->subdivision_current = 0;
walker->subdivision_parent = walker->last_segment;
walker->cursor = walker->subdivision_parent.start.distance_from_start;
/* Copy parent segment start, to be used as first subdivided segment start */
walker->last_segment.end = walker->subdivision_parent.start;
/* Recursive call to get first subdivided segment */
cloudsWalkerPerformStep(walker);
result = 1;
}
else
{
/* Unknown order... */
result = 0;
}
/* Check if we need to loop */
if (result > 0 && walker->skip_void && walker->last_segment.start.global_density == 0.0 && walker->last_segment.end.global_density == 0.0)
{
/* Last segment is considered void, and skipping is enabled */
result = -1;
}
}
return result;
}
void cloudsWalkerOrderStop(CloudsWalker* walker)
{
walker->next_action.order = CLOUD_WALKING_STOP;
}
void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision)
{
if (walker->subdivision_count == 0)
{
walker->next_action.order = CLOUD_WALKING_REFINE;
walker->next_action.precision = precision;
}
}
void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments)
{
if (walker->subdivision_count == 0)
{
walker->next_action.order = CLOUD_WALKING_SUBDIVIDE;
walker->next_action.max_segments = max_segments;
}
}
CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker)
{
return &walker->last_segment;
}
void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data)
{
walker->last_segment.data = data;
while (cloudsWalkerPerformStep(walker))
{
callback(walker);
}
}

View file

@ -1,149 +0,0 @@
#ifndef _PAYSAGES_CLOUDS_WALKING_H_
#define _PAYSAGES_CLOUDS_WALKING_H_
#include "public.h"
#include "Vector3.h"
/**
* Functions to walk through a cloud layer.
*/
typedef struct
{
double distance_from_start;
Vector3 location;
double global_density;
double local_density;
} CloudWalkerPoint;
/**
* Information on a segment yielded by walking.
*/
typedef struct
{
Renderer* renderer;
CloudLayerDefinition* layer;
CloudWalkerPoint start;
CloudWalkerPoint end;
double length;
int refined;
int subdivided;
void* data;
} CloudWalkerStepInfo;
typedef struct CloudsWalker CloudsWalker;
typedef void (*FuncCloudsWalkingCallback)(CloudsWalker* walker);
/**
* Optimize the search limits in a layer.
*
* @param layer The cloud layer
* @param start Start of the search to optimize
* @param end End of the search to optimize
* @return 0 if the search is useless
*/
RENDERINGSHARED_EXPORT int cloudsOptimizeWalkingBounds(CloudLayerDefinition* layer, Vector3* start, Vector3* end);
/**
* Create a cloud walker.
*
* For better performance, the segment should by optimized using cloudsOptimizeWalkingBounds.
* @param renderer Renderer context
* @param layer The cloud layer to traverse
* @param start Start of the walk
* @param end End of the walk
*/
RENDERINGSHARED_EXPORT CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudLayerDefinition* layer, Vector3 start, Vector3 end);
/**
* Delete a cloud walker.
*
* @param walker The walker to free
*/
RENDERINGSHARED_EXPORT void cloudsDeleteWalker(CloudsWalker* walker);
/**
* Define the segment size for next steps.
*
* @param walker The walker to configure
* @param step The step length, negative for automatic
*/
RENDERINGSHARED_EXPORT void cloudsWalkerSetStepSize(CloudsWalker* walker, double step);
/**
* Set the void skipping mode.
*
* @param walker The walker to configure
* @param enabled 1 to enable the void skipping, 0 to disable
*/
RENDERINGSHARED_EXPORT void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled);
/**
* Toggle the local density computing.
*
* When this option is set, the CloudWalkerStepInfo will contain information about local density.
* The automatic setting will set to 1 on subdivided steps, and 0 elsewhere.
* @param walker The walker to configure
* @param enabled 1 to enable local density, 0 to disable it, -1 for automatic setting.
*/
RENDERINGSHARED_EXPORT void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled);
/**
* Perform a single step.
*
* @param walker The walker to use
* @return 1 to continue the loop, 0 to stop
*/
RENDERINGSHARED_EXPORT int cloudsWalkerPerformStep(CloudsWalker* walker);
/**
* Order the walker to stop.
*
* @param walker The walker to use
*/
RENDERINGSHARED_EXPORT void cloudsWalkerOrderStop(CloudsWalker* walker);
/**
* Order the walker to refine the search for cloud entry or exit.
*
* The refinement will next yield a shorter version of the segment, containing only the cloud-inside portion, with a
* tolerance fixed by precision. For an entry point, this will discard the part before cloud entry. For en exit point,
* the portion after this point will be part of the next step, as normal walking resumes.
* @param walker The walker to use
* @param precision Precision wanted for the refinement
*/
RENDERINGSHARED_EXPORT void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision);
/**
* Order the walker to subdivide the previous segment in smaller segments.
*
* Next steps will yield subdivided segments. Once subdivided segments have been processed, normal walking
* will resume automatically.
* @param walker The walker to use
* @param max_segments Maximal number of segments
*/
RENDERINGSHARED_EXPORT void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments);
/**
* Get the last segment information.
*
* @param walker The walker to use
*/
RENDERINGSHARED_EXPORT CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker);
/**
* Start walking automatically through a segment.
*
* The callback will be called with each segment found, giving info and asking for desired alteration on walking.
* @param walker The walker to use
* @param callback Callback to be called with each found segment
* @param data User data that will be passed back in the callback
*/
RENDERINGSHARED_EXPORT void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data);
#endif

View file

@ -1,14 +0,0 @@
#ifndef _PAYSAGES_CLOUDS_PRIVATE_H_
#define _PAYSAGES_CLOUDS_PRIVATE_H_
#include "public.h"
#define CLOUDS_MAX_LAYERS 6
#define MAX_SEGMENT_COUNT 100
void cloudsLayerValidateDefinition(CloudLayerDefinition* definition);
Color cloudsLayerFilterLight(CloudLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light);
Color cloudsApplyLayer(CloudLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end);
#endif

View file

@ -1,28 +0,0 @@
#ifndef _PAYSAGES_CLOUDS_PUBLIC_H_
#define _PAYSAGES_CLOUDS_PUBLIC_H_
#include "../rendering_global.h"
#include "../shared/types.h"
#include "../tools/lighting.h"
#include "SurfaceMaterial.h"
typedef Color (*FuncCloudsGetColor)(Renderer* renderer, Color base, Vector3 start, Vector3 end);
typedef double (*FuncCloudsGetLayerDensity)(Renderer* renderer, CloudLayerDefinition* layer, Vector3 location);
typedef double (*FuncCloudsGetEdgeDensity)(Renderer* renderer, CloudLayerDefinition* layer, Vector3 location, double layer_density);
class CloudsRenderer
{
public:
CloudsDefinition* definition;
FuncCloudsGetColor getColor;
FuncLightingAlterLight alterLight;
FuncCloudsGetLayerDensity getLayerDensity;
FuncCloudsGetEdgeDensity getEdgeDensity;
};
RENDERINGSHARED_EXPORT extern StandardRenderer CloudsRendererClass;
#endif

View file

@ -7,7 +7,6 @@
#include "RenderingScenery.h" #include "RenderingScenery.h"
#include "CameraDefinition.h" #include "CameraDefinition.h"
#include "atmosphere/public.h" #include "atmosphere/public.h"
#include "clouds/public.h"
#include "terrain/public.h" #include "terrain/public.h"
#include "textures/public.h" #include "textures/public.h"
#include "water/public.h" #include "water/public.h"
@ -18,7 +17,7 @@ static void* _renderFirstPass(void* data)
{ {
Renderer* renderer = (Renderer*)data; Renderer* renderer = (Renderer*)data;
sceneryRenderFirstPass(renderer); renderer->rasterize();
renderer->is_rendering = 0; renderer->is_rendering = 0;
return NULL; return NULL;
} }
@ -139,7 +138,6 @@ Renderer::Renderer()
lighting = lightingManagerCreate(); lighting = lightingManagerCreate();
atmosphere = (AtmosphereRenderer*)AtmosphereRendererClass.create(); atmosphere = (AtmosphereRenderer*)AtmosphereRendererClass.create();
clouds = (CloudsRenderer*)CloudsRendererClass.create();
terrain = (TerrainRenderer*)TerrainRendererClass.create(); terrain = (TerrainRenderer*)TerrainRendererClass.create();
textures = (TexturesRenderer*)TexturesRendererClass.create(); textures = (TexturesRenderer*)TexturesRendererClass.create();
water = (WaterRenderer*)WaterRendererClass.create(); water = (WaterRenderer*)WaterRendererClass.create();
@ -151,7 +149,6 @@ Renderer::~Renderer()
lightingManagerDelete(lighting); lightingManagerDelete(lighting);
AtmosphereRendererClass.destroy(atmosphere); AtmosphereRendererClass.destroy(atmosphere);
CloudsRendererClass.destroy(clouds);
TerrainRendererClass.destroy(terrain); TerrainRendererClass.destroy(terrain);
TexturesRendererClass.destroy(textures); TexturesRendererClass.destroy(textures);
WaterRendererClass.destroy(water); WaterRendererClass.destroy(water);
@ -159,10 +156,8 @@ Renderer::~Renderer()
renderDeleteArea(render_area); renderDeleteArea(render_area);
} }
Color Renderer::applyMediumTraversal(Vector3 location, Color color) Color Renderer::applyMediumTraversal(Vector3, Color color)
{ {
color = atmosphere->applyAerialPerspective(this, location, color).final;
color = clouds->getColor(this, color, getCameraLocation(this, location), location);
return color; return color;
} }

View file

@ -9,7 +9,6 @@ class LightingManager;
class AtmosphereRenderer; class AtmosphereRenderer;
class TerrainRenderer; class TerrainRenderer;
class TexturesRenderer; class TexturesRenderer;
class CloudsRenderer;
class WaterRenderer; class WaterRenderer;
class Renderer class Renderer
@ -19,6 +18,7 @@ public:
virtual ~Renderer(); virtual ~Renderer();
virtual void prepare() {} virtual void prepare() {}
virtual void rasterize() {}
virtual void setScenery(Scenery*) {} virtual void setScenery(Scenery*) {}
/* Render base configuration */ /* Render base configuration */
@ -57,7 +57,6 @@ public:
AtmosphereRenderer* atmosphere; AtmosphereRenderer* atmosphere;
TerrainRenderer* terrain; TerrainRenderer* terrain;
TexturesRenderer* textures; TexturesRenderer* textures;
CloudsRenderer* clouds;
WaterRenderer* water; WaterRenderer* water;
/* Custom data */ /* Custom data */

View file

@ -12,11 +12,7 @@ SOURCES += main.cpp \
renderer.cpp \ renderer.cpp \
render.cpp \ render.cpp \
atmosphere/atm_render.cpp \ atmosphere/atm_render.cpp \
atmosphere/atm_raster.cpp \
atmosphere/atm_bruneton.cpp \ atmosphere/atm_bruneton.cpp \
clouds/clo_walking.cpp \
clouds/clo_rendering.cpp \
clouds/clo_density.cpp \
terrain/ter_render.cpp \ terrain/ter_render.cpp \
terrain/ter_raster.cpp \ terrain/ter_raster.cpp \
terrain/ter_painting.cpp \ terrain/ter_painting.cpp \
@ -38,10 +34,6 @@ HEADERS += \
main.h \ main.h \
atmosphere/public.h \ atmosphere/public.h \
atmosphere/private.h \ atmosphere/private.h \
clouds/public.h \
clouds/private.h \
clouds/clo_walking.h \
clouds/clo_density.h \
shared/types.h \ shared/types.h \
terrain/ter_raster.h \ terrain/ter_raster.h \
terrain/public.h \ terrain/public.h \

View file

@ -1,13 +1,12 @@
#include "BaseTestCase.h" #include "BaseTestCase.h"
#include <cmath> #include <cmath>
#include "renderer.h" #include "SoftwareRenderer.h"
#include "clouds/public.h"
#include "clouds/clo_density.h"
#include "clouds/clo_walking.h"
#include "CloudLayerDefinition.h" #include "CloudLayerDefinition.h"
#include "NoiseGenerator.h" #include "NoiseGenerator.h"
#if 0
TEST(Clouds, Density) TEST(Clouds, Density)
{ {
/* Setup */ /* Setup */
@ -448,3 +447,5 @@ TEST(Clouds, WalkingLocal)
ASSERT_DOUBLE_EQ(segment->end.global_density, 0.809016994375); ASSERT_DOUBLE_EQ(segment->end.global_density, 0.809016994375);
ASSERT_DOUBLE_EQ(segment->end.local_density, 0.654508497187); ASSERT_DOUBLE_EQ(segment->end.local_density, 0.654508497187);
} }
#endif