2013-12-29 13:14:49 +00:00
|
|
|
#include "TerrainRayWalker.h"
|
|
|
|
|
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "Scenery.h"
|
|
|
|
#include "TerrainDefinition.h"
|
|
|
|
#include "TexturesDefinition.h"
|
|
|
|
#include "TerrainRenderer.h"
|
|
|
|
#include "TexturesRenderer.h"
|
2013-12-29 17:18:18 +00:00
|
|
|
#include "Matrix4.h"
|
2013-12-29 13:14:49 +00:00
|
|
|
|
|
|
|
TerrainRayWalker::TerrainRayWalker(SoftwareRenderer* renderer):
|
|
|
|
renderer(renderer)
|
|
|
|
{
|
2015-09-10 16:16:57 +00:00
|
|
|
setQuality(0.5);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TerrainRayWalker::setQuality(double displacement_safety, double minimal_step, double maximal_step, double step_factor, double max_distance, double escape_step)
|
|
|
|
{
|
|
|
|
this->displacement_safety = displacement_safety;
|
|
|
|
this->minimal_step = minimal_step;
|
|
|
|
this->maximal_step = maximal_step;
|
|
|
|
this->step_factor = step_factor;
|
|
|
|
this->max_distance = max_distance;
|
|
|
|
this->escape_step = escape_step;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TerrainRayWalker::setQuality(double factor)
|
|
|
|
{
|
|
|
|
setQuality(0.2 + 0.8 * factor,
|
|
|
|
1.0 / (factor * factor * 30.0 + 1.0),
|
|
|
|
50.0 / (factor * 10.0 + 1.0),
|
|
|
|
1.0 / (factor * 10.0 + 1.0),
|
|
|
|
10.0 + factor * 200.0,
|
|
|
|
factor * factor * 100.0);
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TerrainRayWalker::update()
|
|
|
|
{
|
|
|
|
TerrainDefinition* terrain = renderer->getScenery()->getTerrain();
|
|
|
|
HeightInfo info = terrain->getHeightInfo();
|
|
|
|
|
|
|
|
TexturesDefinition* textures = renderer->getScenery()->getTextures();
|
2015-09-10 16:16:57 +00:00
|
|
|
displacement_base = textures->getMaximalDisplacement();
|
2013-12-29 13:14:49 +00:00
|
|
|
|
2015-09-10 16:16:57 +00:00
|
|
|
ymin = info.min_height - displacement_base;
|
|
|
|
ymax = info.max_height + displacement_base;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
static inline Vector3 _getShiftAxis(const Vector3 &direction)
|
|
|
|
{
|
|
|
|
if (fabs(direction.y) > 0.99)
|
|
|
|
{
|
|
|
|
// When the ray is vertical, we choose an arbitrary shift axis
|
|
|
|
return VECTOR_NORTH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return VECTOR_UP.crossProduct(direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:16:57 +00:00
|
|
|
bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, double escape_angle, TerrainHitResult &result)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
|
|
|
TerrainRenderer* terrain_renderer = renderer->getTerrainRenderer();
|
|
|
|
TexturesRenderer* textures_renderer = renderer->getTexturesRenderer();
|
|
|
|
TerrainRenderer::TerrainResult terrain_result;
|
2013-12-29 17:18:18 +00:00
|
|
|
Vector3 cursor, displaced;
|
2013-12-29 13:14:49 +00:00
|
|
|
double diff;
|
2013-12-29 17:18:18 +00:00
|
|
|
Matrix4 shift_matrix;
|
|
|
|
double shift_step = 0.0;
|
2013-12-29 13:14:49 +00:00
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
Vector3 previous_cursor = start;
|
|
|
|
bool hit = false;
|
2015-09-10 16:16:57 +00:00
|
|
|
double step_length = minimal_step;
|
2013-12-29 13:14:49 +00:00
|
|
|
double walked_length = 0.0;
|
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
result.escape_angle = 0.0;
|
|
|
|
if (escape_angle != 0.0)
|
|
|
|
{
|
|
|
|
// Prepare escape
|
2015-09-10 16:16:57 +00:00
|
|
|
shift_step = escape_angle / escape_step;
|
2013-12-29 17:18:18 +00:00
|
|
|
shift_matrix = Matrix4::newRotateAxis(-shift_step, _getShiftAxis(direction));
|
|
|
|
}
|
|
|
|
|
2013-12-29 13:14:49 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
// Perform a step
|
2013-12-29 17:18:18 +00:00
|
|
|
cursor = previous_cursor.add(direction.scale(step_length));
|
2013-12-29 13:14:49 +00:00
|
|
|
|
|
|
|
// Get the terrain info at end (without textures displacement)
|
2013-12-29 17:18:18 +00:00
|
|
|
terrain_result = terrain_renderer->getResult(cursor.x, cursor.z, true, false);
|
|
|
|
diff = cursor.y - terrain_result.location.y;
|
2013-12-29 13:14:49 +00:00
|
|
|
|
|
|
|
// If we are very under the terrain, consider a hit
|
2015-09-10 16:16:57 +00:00
|
|
|
if (diff < -displacement_base * displacement_safety)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
|
|
|
hit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we are close enough to the terrain, apply displacement
|
2015-09-10 16:16:57 +00:00
|
|
|
else if (diff < displacement_base * displacement_safety)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
|
|
|
displaced = textures_renderer->displaceTerrain(terrain_result);
|
2013-12-29 17:18:18 +00:00
|
|
|
diff = cursor.y - displaced.y;
|
|
|
|
hit = diff < 0.0;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hit)
|
|
|
|
{
|
2013-12-29 17:18:18 +00:00
|
|
|
// TODO Refine the hit with dichotomy at high quality
|
2013-12-29 13:14:49 +00:00
|
|
|
/*if (renderer->render_quality > 7)
|
|
|
|
{
|
2013-12-29 17:18:18 +00:00
|
|
|
cursor = refineHit(previous_cursor, cursor, step_length);
|
2013-12-29 13:14:49 +00:00
|
|
|
}*/
|
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
// Shift ray to escape terrain
|
|
|
|
if (escape_angle != 0.0)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
2013-12-29 17:18:18 +00:00
|
|
|
result.escape_angle += shift_step;
|
|
|
|
if (result.escape_angle > escape_angle)
|
|
|
|
{
|
|
|
|
// Too much shifted to escape, make it a hit
|
|
|
|
result.escape_angle = 0.0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
hit = false;
|
|
|
|
direction = shift_matrix.multPoint(direction);
|
|
|
|
previous_cursor = start.add(shift_matrix.multPoint(previous_cursor.sub(start)));
|
|
|
|
}
|
2013-12-29 13:14:49 +00:00
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
result.hit_location = cursor;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Prepare next step
|
2013-12-29 17:18:18 +00:00
|
|
|
previous_cursor = cursor;
|
2013-12-29 13:14:49 +00:00
|
|
|
walked_length += step_length;
|
|
|
|
|
2015-09-10 16:16:57 +00:00
|
|
|
step_length = diff * step_factor;
|
|
|
|
if (step_length < minimal_step)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
2015-09-10 16:16:57 +00:00
|
|
|
step_length = minimal_step;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
2015-09-10 16:16:57 +00:00
|
|
|
else if (step_length > maximal_step)
|
2013-12-29 13:14:49 +00:00
|
|
|
{
|
2015-09-10 16:16:57 +00:00
|
|
|
step_length = maximal_step;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-10 16:16:57 +00:00
|
|
|
} while (not hit and cursor.y < ymax and walked_length < max_distance);
|
2013-12-29 13:14:49 +00:00
|
|
|
|
2013-12-29 17:18:18 +00:00
|
|
|
return hit or result.escape_angle > 0.0;
|
2013-12-29 13:14:49 +00:00
|
|
|
}
|