Refactored cloud renderer (currently not working correctly)
This commit is contained in:
parent
7fecdba313
commit
ff27afe675
30 changed files with 679 additions and 1045 deletions
|
@ -4,7 +4,6 @@
|
|||
#include "desktop_global.h"
|
||||
|
||||
#include "baseformlayer.h"
|
||||
#include "clouds/public.h"
|
||||
class QWidget;
|
||||
|
||||
class FormClouds : public BaseFormLayer
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "tools.h"
|
||||
#include "render.h"
|
||||
#include "atmosphere/public.h"
|
||||
#include "clouds/public.h"
|
||||
#include "terrain/public.h"
|
||||
#include "water/public.h"
|
||||
#include "RenderingScenery.h"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "CloudsAspectPreviewRenderer.h"
|
||||
|
||||
#include "clouds/public.h"
|
||||
#include "atmosphere/public.h"
|
||||
#include "BasePreview.h"
|
||||
#include "Scenery.h"
|
||||
#include "CloudsDefinition.h"
|
||||
#include "CloudLayerDefinition.h"
|
||||
#include "CloudsRenderer.h"
|
||||
|
||||
static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int)
|
||||
{
|
||||
|
@ -61,7 +61,6 @@ CloudsAspectPreviewRenderer::CloudsAspectPreviewRenderer(CloudLayerDefinition* l
|
|||
CloudsDefinition* clouds = getScenery()->getClouds();
|
||||
clouds->clear();
|
||||
clouds->addLayer();
|
||||
CloudsRendererClass.bind(this, clouds);
|
||||
|
||||
render_quality = 6;
|
||||
}
|
||||
|
@ -82,7 +81,7 @@ void CloudsAspectPreviewRenderer::updateEvent()
|
|||
|
||||
prepare();
|
||||
|
||||
clouds->getLayerDensity = _getDensity;
|
||||
//clouds->getLayerDensity = _getDensity;
|
||||
atmosphere->getLightingStatus = _getLightingStatus;
|
||||
atmosphere->applyAerialPerspective = _fakeApplyAerialPerspective;
|
||||
}
|
||||
|
@ -100,5 +99,5 @@ Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double)
|
|||
end.z = start.z;
|
||||
end.y = -start.y;
|
||||
|
||||
return clouds->getColor(this, COLOR_BLUE, start, end);
|
||||
return getCloudsRenderer()->getColor(start, end, COLOR_BLUE);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "CloudsCoveragePreviewRenderer.h"
|
||||
|
||||
#include "clouds/public.h"
|
||||
#include "BasePreview.h"
|
||||
#include "Scenery.h"
|
||||
#include "CloudsDefinition.h"
|
||||
#include "CloudLayerDefinition.h"
|
||||
#include "CloudsRenderer.h"
|
||||
|
||||
Color _fakeApplyLightingToSurface(Renderer*, Vector3, Vector3, SurfaceMaterial*)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ CloudsCoveragePreviewRenderer::CloudsCoveragePreviewRenderer(CloudLayerDefinitio
|
|||
CloudsDefinition* clouds = getScenery()->getClouds();
|
||||
clouds->clear();
|
||||
clouds->addLayer();
|
||||
CloudsRendererClass.bind(this, clouds);
|
||||
}
|
||||
|
||||
void CloudsCoveragePreviewRenderer::bindEvent(BasePreview* preview)
|
||||
|
@ -49,7 +48,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali
|
|||
look.z = 1.0;
|
||||
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
|
||||
{
|
||||
|
@ -60,7 +59,7 @@ Color CloudsCoveragePreviewRenderer::getColor2D(double x, double y, double scali
|
|||
start.y = 1000.0;
|
||||
end.y = -1000.0;
|
||||
|
||||
return clouds->getColor(this, COLOR_BLUE, start, end);
|
||||
return getCloudsRenderer()->getColor(start, end, COLOR_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
80
src/render/software/BaseCloudLayerRenderer.cpp
Normal file
80
src/render/software/BaseCloudLayerRenderer.cpp
Normal 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;
|
||||
}
|
30
src/render/software/BaseCloudLayerRenderer.h
Normal file
30
src/render/software/BaseCloudLayerRenderer.h
Normal 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
|
305
src/render/software/CloudBasicLayerRenderer.cpp
Normal file
305
src/render/software/CloudBasicLayerRenderer.cpp
Normal 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;
|
||||
}
|
26
src/render/software/CloudBasicLayerRenderer.h
Normal file
26
src/render/software/CloudBasicLayerRenderer.h
Normal 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
|
81
src/render/software/CloudsRenderer.cpp
Normal file
81
src/render/software/CloudsRenderer.cpp
Normal 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;
|
||||
}
|
52
src/render/software/CloudsRenderer.h
Normal file
52
src/render/software/CloudsRenderer.h
Normal 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
|
|
@ -1,12 +1,19 @@
|
|||
#include "public.h"
|
||||
#include "private.h"
|
||||
#include "SkyRasterizer.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "../renderer.h"
|
||||
#include "clouds/public.h"
|
||||
#include "Vector3.h"
|
||||
#include "Color.h"
|
||||
#include "SoftwareRenderer.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;
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
void atmosphereRenderSkydome(Renderer* renderer)
|
||||
void SkyRasterizer::rasterize()
|
||||
{
|
||||
int res_i, res_j;
|
||||
int i, j;
|
||||
|
@ -71,7 +78,7 @@ void atmosphereRenderSkydome(Renderer* renderer)
|
|||
vertex4 = v3Add(camera_location, direction);
|
||||
|
||||
/* TODO Triangles at poles */
|
||||
renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, _postProcessFragment, NULL);
|
||||
renderer->pushQuad(renderer, vertex1, vertex4, vertex3, vertex2, (f_RenderFragmentCallback)_postProcessFragment, NULL);
|
||||
}
|
||||
}
|
||||
}
|
22
src/render/software/SkyRasterizer.h
Normal file
22
src/render/software/SkyRasterizer.h
Normal 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
|
|
@ -5,12 +5,14 @@
|
|||
#include "FluidMediumManager.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "CloudsRenderer.h"
|
||||
#include "SkyRasterizer.h"
|
||||
|
||||
|
||||
// Legacy compatibility
|
||||
#include "renderer.h"
|
||||
#include "terrain/public.h"
|
||||
#include "clouds/public.h"
|
||||
#include "terrain/ter_raster.h"
|
||||
#include "textures/public.h"
|
||||
#include "water/public.h"
|
||||
static AtmosphereResult _legacyApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base)
|
||||
|
@ -29,8 +31,9 @@ static Vector3 _legacyGetSunDirection(Renderer* renderer)
|
|||
{
|
||||
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;
|
||||
Color sky_color;
|
||||
|
||||
|
@ -41,7 +44,7 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector
|
|||
|
||||
result.hit = 1;
|
||||
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;
|
||||
|
@ -60,6 +63,7 @@ static double _getPrecision(Renderer* renderer, Vector3 location)
|
|||
SoftwareRenderer::SoftwareRenderer(Scenery* scenery)
|
||||
{
|
||||
atmosphere_renderer = new BaseAtmosphereRenderer(this);
|
||||
clouds_renderer = new CloudsRenderer(this);
|
||||
|
||||
fluid_medium = new FluidMediumManager(this);
|
||||
|
||||
|
@ -78,6 +82,7 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery)
|
|||
SoftwareRenderer::~SoftwareRenderer()
|
||||
{
|
||||
delete atmosphere_renderer;
|
||||
delete clouds_renderer;
|
||||
|
||||
delete fluid_medium;
|
||||
|
||||
|
@ -103,6 +108,10 @@ void SoftwareRenderer::prepare()
|
|||
delete atmosphere_renderer;
|
||||
atmosphere_renderer = new SoftwareBrunetonAtmosphereRenderer(this);
|
||||
|
||||
delete clouds_renderer;
|
||||
clouds_renderer = new CloudsRenderer(this);
|
||||
clouds_renderer->update();
|
||||
|
||||
// Setup transitional renderers (for C-legacy subsystems)
|
||||
rayWalking = _rayWalking;
|
||||
getPrecision = _getPrecision;
|
||||
|
@ -116,7 +125,6 @@ void SoftwareRenderer::prepare()
|
|||
scenery->getCamera()->copy(render_camera);
|
||||
TerrainRendererClass.bind(this, scenery->getTerrain());
|
||||
TexturesRendererClass.bind(this, scenery->getTextures());
|
||||
CloudsRendererClass.bind(this, scenery->getClouds());
|
||||
WaterRendererClass.bind(this, scenery->getWater());
|
||||
|
||||
// Prepare global tools
|
||||
|
@ -124,8 +132,21 @@ void SoftwareRenderer::prepare()
|
|||
//fluid_medium->registerMedium(water_renderer);
|
||||
}
|
||||
|
||||
/*Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color)
|
||||
void SoftwareRenderer::rasterize()
|
||||
{
|
||||
Vector3 eye = cameraGetLocation(scenery->getCamera());
|
||||
return fluid_medium->applyTraversal(eye, location, color);
|
||||
}*/
|
||||
terrainRenderSurface(this);
|
||||
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);*/
|
||||
}
|
||||
|
|
|
@ -33,17 +33,26 @@ public:
|
|||
*/
|
||||
virtual void prepare() override;
|
||||
|
||||
/*!
|
||||
* \brief Start the rasterization process.
|
||||
*/
|
||||
virtual void rasterize() override;
|
||||
|
||||
inline Scenery* getScenery() const {return scenery;}
|
||||
|
||||
inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;}
|
||||
inline CloudsRenderer* getCloudsRenderer() const {return clouds_renderer;}
|
||||
|
||||
inline FluidMediumManager* getFluidMediumManager() const {return fluid_medium;}
|
||||
|
||||
//virtual Color applyMediumTraversal(Vector3 location, Color color) override;
|
||||
virtual Color applyMediumTraversal(Vector3 location, Color color) override;
|
||||
|
||||
private:
|
||||
Scenery* scenery;
|
||||
bool own_scenery;
|
||||
FluidMediumManager* fluid_medium;
|
||||
BaseAtmosphereRenderer* atmosphere_renderer;
|
||||
CloudsRenderer* clouds_renderer;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,13 +16,21 @@ include(../../common.pri)
|
|||
SOURCES += SoftwareRenderer.cpp \
|
||||
FluidMediumInterface.cpp \
|
||||
FluidMediumManager.cpp \
|
||||
AtmosphereRenderer.cpp
|
||||
AtmosphereRenderer.cpp \
|
||||
CloudsRenderer.cpp \
|
||||
BaseCloudLayerRenderer.cpp \
|
||||
SkyRasterizer.cpp \
|
||||
CloudBasicLayerRenderer.cpp
|
||||
|
||||
HEADERS += SoftwareRenderer.h\
|
||||
software_global.h \
|
||||
FluidMediumInterface.h \
|
||||
FluidMediumManager.h \
|
||||
AtmosphereRenderer.h
|
||||
AtmosphereRenderer.h \
|
||||
CloudsRenderer.h \
|
||||
BaseCloudLayerRenderer.h \
|
||||
SkyRasterizer.h \
|
||||
CloudBasicLayerRenderer.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace software {
|
|||
|
||||
class BaseAtmosphereRenderer;
|
||||
class SoftwareBrunetonAtmosphereRenderer;
|
||||
|
||||
class CloudsRenderer;
|
||||
class BaseCloudLayerRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,13 +55,3 @@ void RenderingScenery::bindToRenderer(Renderer* renderer)
|
|||
renderer->setScenery(this);
|
||||
renderer->prepare();
|
||||
}
|
||||
|
||||
|
||||
// Transitional C-API
|
||||
|
||||
void sceneryRenderFirstPass(Renderer* renderer)
|
||||
{
|
||||
terrainRenderSurface(renderer);
|
||||
waterRenderSurface(renderer);
|
||||
atmosphereRenderSkydome(renderer);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,4 @@ private:
|
|||
void* _custom_data;
|
||||
};
|
||||
|
||||
// Transitional C-API
|
||||
|
||||
RENDERINGSHARED_EXPORT void sceneryRenderFirstPass(Renderer* renderer);
|
||||
|
||||
#endif // SCENERY_H
|
||||
|
|
|
@ -38,8 +38,6 @@ public:
|
|||
|
||||
RENDERINGSHARED_EXPORT extern StandardRenderer AtmosphereRendererClass;
|
||||
|
||||
RENDERINGSHARED_EXPORT void atmosphereRenderSkydome(Renderer* renderer);
|
||||
|
||||
RENDERINGSHARED_EXPORT void atmosphereInitResult(AtmosphereResult* result);
|
||||
RENDERINGSHARED_EXPORT void atmosphereUpdateResult(AtmosphereResult* result);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -7,7 +7,6 @@
|
|||
#include "RenderingScenery.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "atmosphere/public.h"
|
||||
#include "clouds/public.h"
|
||||
#include "terrain/public.h"
|
||||
#include "textures/public.h"
|
||||
#include "water/public.h"
|
||||
|
@ -18,7 +17,7 @@ static void* _renderFirstPass(void* data)
|
|||
{
|
||||
Renderer* renderer = (Renderer*)data;
|
||||
|
||||
sceneryRenderFirstPass(renderer);
|
||||
renderer->rasterize();
|
||||
renderer->is_rendering = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -139,7 +138,6 @@ Renderer::Renderer()
|
|||
lighting = lightingManagerCreate();
|
||||
|
||||
atmosphere = (AtmosphereRenderer*)AtmosphereRendererClass.create();
|
||||
clouds = (CloudsRenderer*)CloudsRendererClass.create();
|
||||
terrain = (TerrainRenderer*)TerrainRendererClass.create();
|
||||
textures = (TexturesRenderer*)TexturesRendererClass.create();
|
||||
water = (WaterRenderer*)WaterRendererClass.create();
|
||||
|
@ -151,7 +149,6 @@ Renderer::~Renderer()
|
|||
lightingManagerDelete(lighting);
|
||||
|
||||
AtmosphereRendererClass.destroy(atmosphere);
|
||||
CloudsRendererClass.destroy(clouds);
|
||||
TerrainRendererClass.destroy(terrain);
|
||||
TexturesRendererClass.destroy(textures);
|
||||
WaterRendererClass.destroy(water);
|
||||
|
@ -159,10 +156,8 @@ Renderer::~Renderer()
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ class LightingManager;
|
|||
class AtmosphereRenderer;
|
||||
class TerrainRenderer;
|
||||
class TexturesRenderer;
|
||||
class CloudsRenderer;
|
||||
class WaterRenderer;
|
||||
|
||||
class Renderer
|
||||
|
@ -19,6 +18,7 @@ public:
|
|||
virtual ~Renderer();
|
||||
|
||||
virtual void prepare() {}
|
||||
virtual void rasterize() {}
|
||||
virtual void setScenery(Scenery*) {}
|
||||
|
||||
/* Render base configuration */
|
||||
|
@ -57,7 +57,6 @@ public:
|
|||
AtmosphereRenderer* atmosphere;
|
||||
TerrainRenderer* terrain;
|
||||
TexturesRenderer* textures;
|
||||
CloudsRenderer* clouds;
|
||||
WaterRenderer* water;
|
||||
|
||||
/* Custom data */
|
||||
|
|
|
@ -12,11 +12,7 @@ SOURCES += main.cpp \
|
|||
renderer.cpp \
|
||||
render.cpp \
|
||||
atmosphere/atm_render.cpp \
|
||||
atmosphere/atm_raster.cpp \
|
||||
atmosphere/atm_bruneton.cpp \
|
||||
clouds/clo_walking.cpp \
|
||||
clouds/clo_rendering.cpp \
|
||||
clouds/clo_density.cpp \
|
||||
terrain/ter_render.cpp \
|
||||
terrain/ter_raster.cpp \
|
||||
terrain/ter_painting.cpp \
|
||||
|
@ -38,10 +34,6 @@ HEADERS += \
|
|||
main.h \
|
||||
atmosphere/public.h \
|
||||
atmosphere/private.h \
|
||||
clouds/public.h \
|
||||
clouds/private.h \
|
||||
clouds/clo_walking.h \
|
||||
clouds/clo_density.h \
|
||||
shared/types.h \
|
||||
terrain/ter_raster.h \
|
||||
terrain/public.h \
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#include "BaseTestCase.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "renderer.h"
|
||||
#include "clouds/public.h"
|
||||
#include "clouds/clo_density.h"
|
||||
#include "clouds/clo_walking.h"
|
||||
#include "SoftwareRenderer.h"
|
||||
#include "CloudLayerDefinition.h"
|
||||
#include "NoiseGenerator.h"
|
||||
|
||||
#if 0
|
||||
|
||||
TEST(Clouds, Density)
|
||||
{
|
||||
/* Setup */
|
||||
|
@ -448,3 +447,5 @@ TEST(Clouds, WalkingLocal)
|
|||
ASSERT_DOUBLE_EQ(segment->end.global_density, 0.809016994375);
|
||||
ASSERT_DOUBLE_EQ(segment->end.local_density, 0.654508497187);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue