paysages3d/src/render/software/VegetationRenderer.cpp

159 lines
4.9 KiB
C++
Raw Normal View History

2015-10-18 15:26:19 +00:00
#include "VegetationRenderer.h"
#include "VegetationModelRenderer.h"
#include "RayCastingResult.h"
#include "SpaceGridIterator.h"
#include "SpaceSegment.h"
#include "VegetationInstance.h"
#include "SoftwareRenderer.h"
#include "Scenery.h"
#include "TerrainRenderer.h"
#include "VegetationDefinition.h"
2015-10-18 20:15:19 +00:00
#include "VegetationLayerDefinition.h"
#include "VegetationPresenceDefinition.h"
#include "VegetationInstance.h"
2015-10-18 15:26:19 +00:00
#include "VegetationResult.h"
#include "LightComponent.h"
2015-10-18 20:15:19 +00:00
/**
* Grid iterator to collect instances of a layer, in small squares.
*/
2015-10-18 15:26:19 +00:00
class VegetationGridIterator: public SpaceGridIterator
{
public:
VegetationGridIterator(const SpaceSegment &segment, VegetationRenderer *renderer, bool only_hit):
segment(segment), renderer(renderer), only_hit(only_hit)
2015-10-18 15:26:19 +00:00
{
}
inline const RayCastingResult &getResult() const {return result;}
virtual bool onCell(int x, int, int z) override
{
result = renderer->getBoundResult(segment, (double)x, (double)z, only_hit);
return not result.hit;
2015-10-18 15:26:19 +00:00
}
private:
const SpaceSegment &segment;
VegetationRenderer *renderer;
RayCastingResult result;
bool only_hit;
};
VegetationRenderer::VegetationRenderer(SoftwareRenderer *parent):
parent(parent)
{
enabled = true;
2015-10-18 15:26:19 +00:00
}
void VegetationRenderer::setEnabled(bool enabled)
{
this->enabled = enabled;
}
2015-10-18 20:15:19 +00:00
RayCastingResult VegetationRenderer::renderInstance(const SpaceSegment &segment, const VegetationInstance &instance, bool only_hit, bool displaced)
2015-10-18 15:26:19 +00:00
{
2015-10-18 20:15:19 +00:00
if (!displaced)
{
// Recursive call on displaced instance
const Vector3 &base = instance.getBase();
TerrainRenderer::TerrainResult terrain = parent->getTerrainRenderer()->getResult(base.x, base.z, true, true);
VegetationInstance displaced_instance = instance.displace(terrain.location, terrain.normal);
return renderInstance(segment, displaced_instance, only_hit, true);
}
2015-10-18 15:26:19 +00:00
2015-10-18 20:15:19 +00:00
RayCastingResult final;
2015-10-18 15:26:19 +00:00
VegetationModelRenderer model_renderer(parent, &instance.getModel());
SpaceSegment scaled_segment(segment.getStart().sub(instance.getBase()).scale(1.0 / instance.getSize()),
segment.getEnd().sub(instance.getBase()).scale(1.0 / instance.getSize()));
VegetationResult result = model_renderer.getResult(scaled_segment, only_hit);
final.hit = result.isHit();
if (final.hit and not only_hit)
{
Vector3 location = result.getLocation().scale(instance.getSize()).add(instance.getBase());
final.hit_color = parent->applyLightingToSurface(location, result.getNormal(), result.getMaterial());
final.hit_color = parent->applyMediumTraversal(location, final.hit_color);
final.hit_location = result.getLocation();
}
return final;
}
RayCastingResult VegetationRenderer::getResult(const SpaceSegment &segment, bool only_hit)
{
if (enabled)
2015-10-18 15:26:19 +00:00
{
// Find instances potentially crossing the segment
VegetationGridIterator it(segment, this, only_hit);
if (not segment.projectedOnYPlane().iterateOnGrid(it))
{
return it.getResult();
}
2015-10-18 20:15:19 +00:00
return RayCastingResult();
2015-10-18 15:26:19 +00:00
}
else
{
return RayCastingResult();
}
}
RayCastingResult VegetationRenderer::getBoundResult(const SpaceSegment &segment, double x, double z, bool only_hit, double xsize, double zsize)
{
// Early check if we may cross any vegetation
double ymin, ymax;
double vegetation_max_height = 0.0; // TODO
parent->getTerrainRenderer()->estimateMinMaxHeight(x, z, x + xsize, z + zsize, &ymin, &ymax);
ymax += vegetation_max_height;
SpaceSegment bbox(Vector3(x, ymin, z), Vector3(x + xsize, ymax, z + zsize));
if (not segment.intersectBoundingBox(bbox)) {
return RayCastingResult();
}
// Iterate all layers and instances
VegetationDefinition *vegetation = parent->getScenery()->getVegetation();
int n = vegetation->count();
for (int i = 0; i < n; i++)
{
VegetationLayerDefinition *layer = vegetation->getVegetationLayer(i);
std::vector<VegetationInstance> instances;
layer->getPresence()->collectInstances(&instances, *layer->getModel(), x, z, x + xsize, z + zsize);
for (auto &instance: instances)
{
RayCastingResult result = renderInstance(segment, instance, only_hit);
if (result.hit)
{
// TODO Don't stop at first hit, find the nearest one
return result;
}
}
}
return RayCastingResult();
}
2015-10-18 15:26:19 +00:00
bool VegetationRenderer::applyLightFilter(LightComponent &light, const Vector3 &at)
{
if (enabled)
2015-10-18 15:26:19 +00:00
{
// Get segment to iterate
SpaceSegment segment(at, at.add(light.direction.scale(-1.0 * parent->render_quality)));
if (getResult(segment, true).hit)
{
light.color = COLOR_BLACK;
return false;
}
else
{
return true;
}
2015-10-18 15:26:19 +00:00
}
else
{
return true;
}
}