Refactored quality control of terrain rendering
Terrain scaling factor was removed for quality consistency
This commit is contained in:
parent
4fcf1d071c
commit
6a45c5dba7
12 changed files with 114 additions and 113 deletions
|
@ -9,7 +9,6 @@ TerrainDefinition::TerrainDefinition(DefinitionNode* parent):
|
||||||
DefinitionNode(parent, "terrain", "terrain")
|
DefinitionNode(parent, "terrain", "terrain")
|
||||||
{
|
{
|
||||||
height = 1.0;
|
height = 1.0;
|
||||||
scaling = 1.0;
|
|
||||||
shadow_smoothing = 0.0;
|
shadow_smoothing = 0.0;
|
||||||
|
|
||||||
height_map = new TerrainHeightMap(this);
|
height_map = new TerrainHeightMap(this);
|
||||||
|
@ -36,8 +35,8 @@ void TerrainDefinition::validate()
|
||||||
|
|
||||||
/* Get minimal and maximal height */
|
/* Get minimal and maximal height */
|
||||||
_height_noise->getRange(&_min_height, &_max_height);
|
_height_noise->getRange(&_min_height, &_max_height);
|
||||||
_min_height *= height * scaling;
|
_min_height *= height;
|
||||||
_max_height *= height * scaling;
|
_max_height *= height;
|
||||||
|
|
||||||
/* TODO Alter with heightmap min/max */
|
/* TODO Alter with heightmap min/max */
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,6 @@ void TerrainDefinition::copy(DefinitionNode* _destination) const
|
||||||
TerrainDefinition* destination = (TerrainDefinition*)_destination;
|
TerrainDefinition* destination = (TerrainDefinition*)_destination;
|
||||||
|
|
||||||
destination->height = height;
|
destination->height = height;
|
||||||
destination->scaling = scaling;
|
|
||||||
destination->shadow_smoothing = shadow_smoothing;
|
destination->shadow_smoothing = shadow_smoothing;
|
||||||
|
|
||||||
height_map->copy(destination->height_map);
|
height_map->copy(destination->height_map);
|
||||||
|
@ -62,7 +60,6 @@ void TerrainDefinition::save(PackStream* stream) const
|
||||||
DefinitionNode::save(stream);
|
DefinitionNode::save(stream);
|
||||||
|
|
||||||
stream->write(&height);
|
stream->write(&height);
|
||||||
stream->write(&scaling);
|
|
||||||
stream->write(&shadow_smoothing);
|
stream->write(&shadow_smoothing);
|
||||||
_height_noise->save(stream);
|
_height_noise->save(stream);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +69,6 @@ void TerrainDefinition::load(PackStream* stream)
|
||||||
DefinitionNode::load(stream);
|
DefinitionNode::load(stream);
|
||||||
|
|
||||||
stream->read(&height);
|
stream->read(&height);
|
||||||
stream->read(&scaling);
|
|
||||||
stream->read(&shadow_smoothing);
|
stream->read(&shadow_smoothing);
|
||||||
_height_noise->load(stream);
|
_height_noise->load(stream);
|
||||||
|
|
||||||
|
@ -94,8 +90,6 @@ double TerrainDefinition::getGridHeight(int x, int z, bool with_painting)
|
||||||
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting, bool water_offset)
|
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting, bool water_offset)
|
||||||
{
|
{
|
||||||
double h;
|
double h;
|
||||||
x /= scaling;
|
|
||||||
z /= scaling;
|
|
||||||
|
|
||||||
if (!with_painting || !height_map->getInterpolatedValue(x, z, &h))
|
if (!with_painting || !height_map->getInterpolatedValue(x, z, &h))
|
||||||
{
|
{
|
||||||
|
@ -104,7 +98,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled,
|
||||||
|
|
||||||
if (scaled)
|
if (scaled)
|
||||||
{
|
{
|
||||||
return (water_offset ? (h - water_height->getValue()) : h) * height * scaling;
|
return (water_offset ? (h - water_height->getValue()) : h) * height;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -114,7 +108,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled,
|
||||||
|
|
||||||
double TerrainDefinition::getWaterOffset() const
|
double TerrainDefinition::getWaterOffset() const
|
||||||
{
|
{
|
||||||
return -water_height->getValue() * height * scaling;
|
return -water_height->getValue() * height;
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightInfo TerrainDefinition::getHeightInfo()
|
HeightInfo TerrainDefinition::getHeightInfo()
|
||||||
|
@ -123,7 +117,6 @@ HeightInfo TerrainDefinition::getHeightInfo()
|
||||||
|
|
||||||
result.min_height = _min_height;
|
result.min_height = _min_height;
|
||||||
result.max_height = _max_height;
|
result.max_height = _max_height;
|
||||||
/* TODO This is duplicated in ter_render.c (_realGetWaterHeight) */
|
|
||||||
result.base_height = -getWaterOffset();
|
result.base_height = -getWaterOffset();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -146,7 +139,6 @@ void TerrainDefinition::applyPreset(TerrainPreset preset)
|
||||||
_height_noise->addLevelsSimple(resolution - 2, pow(2.0, resolution - 1), -0.7, 0.7, 0.5);
|
_height_noise->addLevelsSimple(resolution - 2, pow(2.0, resolution - 1), -0.7, 0.7, 0.5);
|
||||||
_height_noise->normalizeAmplitude(-1.0, 1.0, 0);
|
_height_noise->normalizeAmplitude(-1.0, 1.0, 0);
|
||||||
_height_noise->setFunctionParams(NoiseGenerator::NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
|
_height_noise->setFunctionParams(NoiseGenerator::NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
|
||||||
scaling = 1.0;
|
|
||||||
height = 30.0;
|
height = 30.0;
|
||||||
shadow_smoothing = 0.03;
|
shadow_smoothing = 0.03;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -44,7 +44,6 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
double height;
|
double height;
|
||||||
double scaling;
|
|
||||||
double shadow_smoothing;
|
double shadow_smoothing;
|
||||||
|
|
||||||
TerrainHeightMap* height_map;
|
TerrainHeightMap* height_map;
|
||||||
|
|
|
@ -19,7 +19,7 @@ void TerrainHeightMap::copy(DefinitionNode* _destination) const
|
||||||
|
|
||||||
double TerrainHeightMap::getInitialValue(double x, double y) const
|
double TerrainHeightMap::getInitialValue(double x, double y) const
|
||||||
{
|
{
|
||||||
return terrain->getInterpolatedHeight(x * terrain->scaling, y * terrain->scaling, false, false);
|
return terrain->getInterpolatedHeight(x, y, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainHeightMap::brushElevation(const PaintedGridBrush &brush, double x, double y, double value)
|
void TerrainHeightMap::brushElevation(const PaintedGridBrush &brush, double x, double y, double value)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "SoftwareCanvasRenderer.h"
|
#include "SoftwareCanvasRenderer.h"
|
||||||
|
#include "TerrainRenderer.h"
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
#include "TerrainDefinition.h"
|
#include "TerrainDefinition.h"
|
||||||
|
@ -56,10 +57,11 @@ static void testGroundShadowQuality()
|
||||||
|
|
||||||
SoftwareCanvasRenderer renderer(&scenery);
|
SoftwareCanvasRenderer renderer(&scenery);
|
||||||
renderer.setSize(400, 300);
|
renderer.setSize(400, 300);
|
||||||
for (int i = 1; i <= 10; i++)
|
renderer.setQuality(0.2);
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
// TODO keep same rasterization across renders, or keep rasterization quality low
|
// TODO keep same rasterization across renders, or keep rasterization quality low
|
||||||
renderer.render_quality = i;
|
renderer.getTerrainRenderer()->setQuality((double)i / 5.0);
|
||||||
startTestRender(&renderer, "ground_shadow_quality", i);
|
startTestRender(&renderer, "ground_shadow_quality", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
|
||||||
|
|
||||||
view_matrix = new QMatrix4x4;
|
view_matrix = new QMatrix4x4;
|
||||||
|
|
||||||
render_quality = 3;
|
setQuality(0.3);
|
||||||
|
|
||||||
functions = new OpenGLFunctions();
|
functions = new OpenGLFunctions();
|
||||||
shared_state = new OpenGLSharedState();
|
shared_state = new OpenGLSharedState();
|
||||||
|
|
|
@ -86,6 +86,14 @@ void SoftwareRenderer::prepare()
|
||||||
//fluid_medium->registerMedium(water_renderer);
|
//fluid_medium->registerMedium(water_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftwareRenderer::setQuality(double quality)
|
||||||
|
{
|
||||||
|
terrain_renderer->setQuality(quality);
|
||||||
|
|
||||||
|
// TEMP compat with old code
|
||||||
|
render_quality = (int)(quality * 9.0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareRenderer::disableAtmosphere()
|
void SoftwareRenderer::disableAtmosphere()
|
||||||
{
|
{
|
||||||
LightComponent light;
|
LightComponent light;
|
||||||
|
|
|
@ -22,8 +22,6 @@ public:
|
||||||
int render_quality;
|
int render_quality;
|
||||||
CameraDefinition* render_camera;
|
CameraDefinition* render_camera;
|
||||||
|
|
||||||
void* customData[10];
|
|
||||||
|
|
||||||
virtual Vector3 getCameraLocation(const Vector3 &target);
|
virtual Vector3 getCameraLocation(const Vector3 &target);
|
||||||
virtual Vector3 getCameraDirection(const Vector3 &target);
|
virtual Vector3 getCameraDirection(const Vector3 &target);
|
||||||
virtual double getPrecision(const Vector3 &location);
|
virtual double getPrecision(const Vector3 &location);
|
||||||
|
@ -38,6 +36,15 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void prepare();
|
virtual void prepare();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the global quality control factor.
|
||||||
|
*
|
||||||
|
* Values between 0.0 and 1.0 are standard quality (1.0 is considered a "very good" production quality value).
|
||||||
|
*
|
||||||
|
* Values above 1.0 are used for boosting ("extra" quality, for demanding renders).
|
||||||
|
*/
|
||||||
|
virtual void setQuality(double quality);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Disable atmosphere and sky lighting, replacing it by static lights.
|
* \brief Disable atmosphere and sky lighting, replacing it by static lights.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,6 +11,27 @@
|
||||||
TerrainRayWalker::TerrainRayWalker(SoftwareRenderer* renderer):
|
TerrainRayWalker::TerrainRayWalker(SoftwareRenderer* renderer):
|
||||||
renderer(renderer)
|
renderer(renderer)
|
||||||
{
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainRayWalker::update()
|
void TerrainRayWalker::update()
|
||||||
|
@ -19,16 +40,10 @@ void TerrainRayWalker::update()
|
||||||
HeightInfo info = terrain->getHeightInfo();
|
HeightInfo info = terrain->getHeightInfo();
|
||||||
|
|
||||||
TexturesDefinition* textures = renderer->getScenery()->getTextures();
|
TexturesDefinition* textures = renderer->getScenery()->getTextures();
|
||||||
double disp = textures->getMaximalDisplacement();
|
displacement_base = textures->getMaximalDisplacement();
|
||||||
|
|
||||||
ymin = info.min_height - disp;
|
ymin = info.min_height - displacement_base;
|
||||||
ymax = info.max_height + disp;
|
ymax = info.max_height + displacement_base;
|
||||||
|
|
||||||
ydispmax = disp * (0.5 + (double)renderer->render_quality * 0.05);
|
|
||||||
ydispmin = -ydispmax;
|
|
||||||
|
|
||||||
minstep = 0.5 * terrain->scaling / (double)renderer->render_quality;
|
|
||||||
maxstep = 50.0 * terrain->scaling / (double)renderer->render_quality;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Vector3 _getShiftAxis(const Vector3 &direction)
|
static inline Vector3 _getShiftAxis(const Vector3 &direction)
|
||||||
|
@ -44,7 +59,7 @@ static inline Vector3 _getShiftAxis(const Vector3 &direction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, double escape_angle, double max_length, TerrainHitResult &result)
|
bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, double escape_angle, TerrainHitResult &result)
|
||||||
{
|
{
|
||||||
TerrainRenderer* terrain_renderer = renderer->getTerrainRenderer();
|
TerrainRenderer* terrain_renderer = renderer->getTerrainRenderer();
|
||||||
TexturesRenderer* textures_renderer = renderer->getTexturesRenderer();
|
TexturesRenderer* textures_renderer = renderer->getTexturesRenderer();
|
||||||
|
@ -56,21 +71,14 @@ bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, dou
|
||||||
|
|
||||||
Vector3 previous_cursor = start;
|
Vector3 previous_cursor = start;
|
||||||
bool hit = false;
|
bool hit = false;
|
||||||
double step_length = minstep;
|
double step_length = minimal_step;
|
||||||
double walked_length = 0.0;
|
double walked_length = 0.0;
|
||||||
|
|
||||||
result.escape_angle = 0.0;
|
result.escape_angle = 0.0;
|
||||||
if (escape_angle != 0.0)
|
if (escape_angle != 0.0)
|
||||||
{
|
{
|
||||||
// Prepare escape
|
// Prepare escape
|
||||||
if (renderer->render_quality >= 7)
|
shift_step = escape_angle / escape_step;
|
||||||
{
|
|
||||||
shift_step = escape_angle / (double)(renderer->render_quality * renderer->render_quality);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
shift_step = escape_angle / (double)renderer->render_quality;
|
|
||||||
}
|
|
||||||
shift_matrix = Matrix4::newRotateAxis(-shift_step, _getShiftAxis(direction));
|
shift_matrix = Matrix4::newRotateAxis(-shift_step, _getShiftAxis(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,13 +92,13 @@ bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, dou
|
||||||
diff = cursor.y - terrain_result.location.y;
|
diff = cursor.y - terrain_result.location.y;
|
||||||
|
|
||||||
// If we are very under the terrain, consider a hit
|
// If we are very under the terrain, consider a hit
|
||||||
if (diff < ydispmin)
|
if (diff < -displacement_base * displacement_safety)
|
||||||
{
|
{
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are close enough to the terrain, apply displacement
|
// If we are close enough to the terrain, apply displacement
|
||||||
else if (diff < ydispmax)
|
else if (diff < displacement_base * displacement_safety)
|
||||||
{
|
{
|
||||||
displaced = textures_renderer->displaceTerrain(terrain_result);
|
displaced = textures_renderer->displaceTerrain(terrain_result);
|
||||||
diff = cursor.y - displaced.y;
|
diff = cursor.y - displaced.y;
|
||||||
|
@ -128,17 +136,17 @@ bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, dou
|
||||||
previous_cursor = cursor;
|
previous_cursor = cursor;
|
||||||
walked_length += step_length;
|
walked_length += step_length;
|
||||||
|
|
||||||
step_length = diff * 10.0 / (double)renderer->render_quality;
|
step_length = diff * step_factor;
|
||||||
if (step_length < minstep)
|
if (step_length < minimal_step)
|
||||||
{
|
{
|
||||||
step_length = minstep;
|
step_length = minimal_step;
|
||||||
}
|
}
|
||||||
else if (step_length > maxstep)
|
else if (step_length > maximal_step)
|
||||||
{
|
{
|
||||||
step_length = maxstep;
|
step_length = maximal_step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (not hit and cursor.y < ymax and walked_length < max_length);
|
} while (not hit and cursor.y < ymax and walked_length < max_distance);
|
||||||
|
|
||||||
return hit or result.escape_angle > 0.0;
|
return hit or result.escape_angle > 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,19 @@ public:
|
||||||
public:
|
public:
|
||||||
TerrainRayWalker(SoftwareRenderer* renderer);
|
TerrainRayWalker(SoftwareRenderer* renderer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the walker quality.
|
||||||
|
*
|
||||||
|
* @param displacement_safety Safety factor (around 1.0) to detect when displacement textures need to be applied
|
||||||
|
* @param minimal_step Minimal length of a walking step
|
||||||
|
* @param maximal_step Maximal length of a walking step
|
||||||
|
* @param step_factor Precision factor of steps, depending on terrain proximity
|
||||||
|
* @param max_distance Maximal distance allowed to travel before considering an escape
|
||||||
|
* @param escape_step Angle step when allowing an escape angle
|
||||||
|
*/
|
||||||
|
void setQuality(double displacement_safety, double minimal_step, double maximal_step, double step_factor, double max_distance, double escape_step);
|
||||||
|
void setQuality(double factor);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Update the walker internal data, from the renderer and scenery.
|
* \brief Update the walker internal data, from the renderer and scenery.
|
||||||
*/
|
*/
|
||||||
|
@ -37,20 +50,24 @@ public:
|
||||||
* \param start Point of origin of the ray
|
* \param start Point of origin of the ray
|
||||||
* \param direction Ray direction (normalized vector)
|
* \param direction Ray direction (normalized vector)
|
||||||
* \param escape_angle Maximal angle allowed to escape the terrain on hit (mainly for shadows computing)
|
* \param escape_angle Maximal angle allowed to escape the terrain on hit (mainly for shadows computing)
|
||||||
* \param max_length Maximum length to walk before considering no hit
|
|
||||||
* \param result Object to store the results info
|
* \param result Object to store the results info
|
||||||
* \return true if there was a hit
|
* \return true if there was a hit
|
||||||
*/
|
*/
|
||||||
bool startWalking(const Vector3 &start, Vector3 direction, double escape_angle, double max_length, TerrainHitResult &result);
|
bool startWalking(const Vector3 &start, Vector3 direction, double escape_angle, TerrainHitResult &result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SoftwareRenderer* renderer;
|
SoftwareRenderer* renderer;
|
||||||
double ymin;
|
double ymin;
|
||||||
double ymax;
|
double ymax;
|
||||||
double ydispmin;
|
double displacement_base;
|
||||||
double ydispmax;
|
|
||||||
double minstep;
|
// Quality control
|
||||||
double maxstep;
|
double displacement_safety;
|
||||||
|
double minimal_step;
|
||||||
|
double maximal_step;
|
||||||
|
double step_factor;
|
||||||
|
double max_distance;
|
||||||
|
double escape_step;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,34 @@
|
||||||
TerrainRenderer::TerrainRenderer(SoftwareRenderer* parent):
|
TerrainRenderer::TerrainRenderer(SoftwareRenderer* parent):
|
||||||
parent(parent)
|
parent(parent)
|
||||||
{
|
{
|
||||||
walker = new TerrainRayWalker(parent);
|
walker_ray = new TerrainRayWalker(parent);
|
||||||
|
walker_shadows = new TerrainRayWalker(parent);
|
||||||
|
quad_normals = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainRenderer::~TerrainRenderer()
|
TerrainRenderer::~TerrainRenderer()
|
||||||
{
|
{
|
||||||
delete walker;
|
delete walker_ray;
|
||||||
|
delete walker_shadows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainRenderer::update()
|
void TerrainRenderer::update()
|
||||||
{
|
{
|
||||||
walker->update();
|
walker_ray->update();
|
||||||
|
walker_shadows->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainRenderer::setQuality(bool quad_normals, double ray_precision, double shadow_precision)
|
||||||
|
{
|
||||||
|
this->quad_normals = quad_normals;
|
||||||
|
|
||||||
|
walker_ray->setQuality(ray_precision);
|
||||||
|
walker_shadows->setQuality(shadow_precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainRenderer::setQuality(double factor)
|
||||||
|
{
|
||||||
|
setQuality(factor > 0.6, factor, factor * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
double TerrainRenderer::getHeight(double x, double z, bool with_painting, bool water_offset)
|
double TerrainRenderer::getHeight(double x, double z, bool with_painting, bool water_offset)
|
||||||
|
@ -135,7 +152,7 @@ RayCastingResult TerrainRenderer::castRay(const Vector3 &start, const Vector3 &d
|
||||||
{
|
{
|
||||||
RayCastingResult result;
|
RayCastingResult result;
|
||||||
TerrainRayWalker::TerrainHitResult walk_result;
|
TerrainRayWalker::TerrainHitResult walk_result;
|
||||||
if (walker->startWalking(start, direction.normalize(), 0.0, 200.0, walk_result))
|
if (walker_ray->startWalking(start, direction.normalize(), 0.0, walk_result))
|
||||||
{
|
{
|
||||||
result.hit = true;
|
result.hit = true;
|
||||||
result.hit_location = walk_result.hit_location;
|
result.hit_location = walk_result.hit_location;
|
||||||
|
@ -176,7 +193,7 @@ bool TerrainRenderer::applyLightFilter(LightComponent &light, const Vector3 &at)
|
||||||
// Walk to find an intersection
|
// Walk to find an intersection
|
||||||
double escape_angle = definition->shadow_smoothing;
|
double escape_angle = definition->shadow_smoothing;
|
||||||
// TODO max length should depend on the sun light angle and altitude range
|
// TODO max length should depend on the sun light angle and altitude range
|
||||||
if (walker->startWalking(at, direction_to_light, escape_angle, 100.0, walk_result))
|
if (walker_shadows->startWalking(at, direction_to_light, escape_angle, walk_result))
|
||||||
{
|
{
|
||||||
if (walk_result.escape_angle == 0.0)
|
if (walk_result.escape_angle == 0.0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,8 @@ public:
|
||||||
virtual ~TerrainRenderer();
|
virtual ~TerrainRenderer();
|
||||||
|
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
void setQuality(bool quad_normals, double ray_precision, double shadow_precision);
|
||||||
|
void setQuality(double factor);
|
||||||
|
|
||||||
virtual RayCastingResult castRay(const Vector3 &start, const Vector3 &direction);
|
virtual RayCastingResult castRay(const Vector3 &start, const Vector3 &direction);
|
||||||
virtual double getHeight(double x, double z, bool with_painting, bool water_offset=true);
|
virtual double getHeight(double x, double z, bool with_painting, bool water_offset=true);
|
||||||
|
@ -33,8 +35,11 @@ public:
|
||||||
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override;
|
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SoftwareRenderer* parent;
|
SoftwareRenderer *parent;
|
||||||
TerrainRayWalker* walker;
|
TerrainRayWalker *walker_ray;
|
||||||
|
TerrainRayWalker *walker_shadows;
|
||||||
|
|
||||||
|
bool quad_normals;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ protected:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
terrain = new TerrainDefinition(NULL);
|
terrain = new TerrainDefinition(NULL);
|
||||||
terrain->height = 3.0;
|
terrain->height = 3.0;
|
||||||
terrain->scaling = 1.0;
|
|
||||||
terrain->_height_noise->clearLevels();
|
terrain->_height_noise->clearLevels();
|
||||||
terrain->propWaterHeight()->setValue(0.0);
|
terrain->propWaterHeight()->setValue(0.0);
|
||||||
NoiseGenerator::NoiseLevel level = {1.0, 2.0, -1.0};
|
NoiseGenerator::NoiseLevel level = {1.0, 2.0, -1.0};
|
||||||
|
@ -74,21 +73,6 @@ TEST_F(TerrainPainting_Test, grid)
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0.0, 0.0, 1, 0), 0.0);
|
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0.0, 0.0, 1, 0), 0.0);
|
||||||
EXPECT_DOUBLE_IN_RANGE(terrain->getInterpolatedHeight(0.5, 0.0, 1, 0), 3.0 * 0.1564, 3.0 * 0.1566);
|
EXPECT_DOUBLE_IN_RANGE(terrain->getInterpolatedHeight(0.5, 0.0, 1, 0), 3.0 * 0.1564, 3.0 * 0.1566);
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1.0, 0.0, 1, 0), 3.0 * sin(1.0 * X_FACTOR));
|
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1.0, 0.0, 1, 0), 3.0 * sin(1.0 * X_FACTOR));
|
||||||
|
|
||||||
/* Test scaling */
|
|
||||||
terrain->scaling = 2.0;
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(0, 0, 0), 0.0);
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(1, 0, 0), sin(1.0 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(2, 0, 0), sin(2.0 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getGridHeight(3, 0, 0), sin(3.0 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0, 0, 0, 0), 0.0);
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1, 0, 0, 0), sin(0.5 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(2, 0, 0, 0), sin(1.0 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(3, 0, 0, 0), sin(1.5 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0, 0, 1, 0), 0.0);
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1, 0, 1, 0), 6.0 * sin(0.5 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(2, 0, 1, 0), 6.0 * sin(1.0 * X_FACTOR));
|
|
||||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(3, 0, 1, 0), 6.0 * sin(1.5 * X_FACTOR));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _checkBrushResultSides(TerrainDefinition* terrain, PaintedGridBrush*, double center, double midhard, double hard, double midsoft, double soft, double exter, double neg_midhard, double neg_hard, double neg_midsoft, double neg_soft, double neg_exter)
|
static void _checkBrushResultSides(TerrainDefinition* terrain, PaintedGridBrush*, double center, double midhard, double hard, double midsoft, double soft, double exter, double neg_midhard, double neg_hard, double neg_midsoft, double neg_soft, double neg_exter)
|
||||||
|
@ -125,7 +109,6 @@ TEST_F(TerrainPainting_Test, brush_flatten)
|
||||||
/* Set up */
|
/* Set up */
|
||||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||||
terrain->height = 1.0;
|
terrain->height = 1.0;
|
||||||
terrain->scaling = 1.0;
|
|
||||||
terrain->_height_noise->forceValue(0.0);
|
terrain->_height_noise->forceValue(0.0);
|
||||||
|
|
||||||
/* Test flattening center at 0.5 */
|
/* Test flattening center at 0.5 */
|
||||||
|
@ -149,14 +132,6 @@ TEST_F(TerrainPainting_Test, brush_flatten)
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
||||||
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||||
|
|
||||||
/* Test with scaling modifier */
|
|
||||||
terrain->height = 10.0;
|
|
||||||
terrain->scaling = 2.0;
|
|
||||||
terrain->height_map->clearPainting();
|
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
|
||||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0);
|
|
||||||
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TerrainPainting_Test, brush_reset)
|
TEST_F(TerrainPainting_Test, brush_reset)
|
||||||
|
@ -165,7 +140,6 @@ TEST_F(TerrainPainting_Test, brush_reset)
|
||||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||||
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||||
terrain->height = 1.0;
|
terrain->height = 1.0;
|
||||||
terrain->scaling = 1.0;
|
|
||||||
terrain->_height_noise->forceValue(1.0);
|
terrain->_height_noise->forceValue(1.0);
|
||||||
|
|
||||||
/* Test resetting at center */
|
/* Test resetting at center */
|
||||||
|
@ -195,32 +169,4 @@ TEST_F(TerrainPainting_Test, brush_reset)
|
||||||
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
||||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
||||||
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||||
|
|
||||||
/* Test with scaling modifier */
|
|
||||||
terrain->height = 10.0;
|
|
||||||
terrain->scaling = 2.0;
|
|
||||||
terrain->height_map->clearPainting();
|
|
||||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
|
||||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
|
||||||
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
|
||||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1);
|
|
||||||
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TerrainPainting_Test, brush_reset_basevalue)
|
|
||||||
{
|
|
||||||
/* Set up */
|
|
||||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
|
||||||
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
|
||||||
terrain->height = 1.0;
|
|
||||||
terrain->scaling = 1.0;
|
|
||||||
|
|
||||||
/* Test with scaling and the sinusoid setup (to test the basevalue sampling) */
|
|
||||||
terrain->height = 1.0;
|
|
||||||
terrain->scaling = 2.0;
|
|
||||||
_checkBrushResult(terrain, &brush, 0.0, 0.309016994375, 0.587785252292, 0.809016994375, 0.951056516295, 1.0, 1);
|
|
||||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0);
|
|
||||||
_checkBrushResultSides(terrain, &brush, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, -1.0);
|
|
||||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 1.0);
|
|
||||||
_checkBrushResultSides(terrain, &brush, 0.0, 0.309016994375, 0.587785252292, 2.0 - (2.0 - 0.809016994375) * 0.5, 2.0, 1.0, -0.309016994375, -0.587785252292, 2.0 - (2.0 + 0.809016994375) * 0.5, 2.0, -1.0);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue