New terrain walker (now used for ray casting)

This commit is contained in:
Michaël Lemaire 2013-12-29 14:14:49 +01:00
parent ce7aa1e179
commit eabe68b77d
13 changed files with 200 additions and 271 deletions

View file

@ -64,3 +64,14 @@ void TexturesDefinition::applyPreset(TexturesPreset preset)
/* TODO */ /* TODO */
} }
} }
double TexturesDefinition::getMaximalDisplacement()
{
double result = 0.0;
int n = count();
for (int i = 0; i < n; i++)
{
result += getTextureLayer(i)->displacement_height;
}
return result;
}

View file

@ -23,6 +23,8 @@ public:
TEXTURES_PRESET_CANYON TEXTURES_PRESET_CANYON
} TexturesPreset; } TexturesPreset;
void applyPreset(TexturesPreset preset); void applyPreset(TexturesPreset preset);
double getMaximalDisplacement();
}; };
} }

View file

@ -11,7 +11,6 @@
#include <QTranslator> #include <QTranslator>
#include <QLocale> #include <QLocale>
#include <QMessageBox> #include <QMessageBox>
#include <QSplashScreen>
#include "BasePreview.h" #include "BasePreview.h"
#include "PreviewOsd.h" #include "PreviewOsd.h"
@ -36,7 +35,6 @@ MainWindow* MainWindow::_instance = NULL;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
MainWindow* window; MainWindow* window;
QSplashScreen* splash;
int result; int result;
QApplication app(argc, argv); QApplication app(argc, argv);
@ -47,9 +45,6 @@ int main(int argc, char** argv)
return 1; return 1;
} }
splash = new QSplashScreen(QPixmap(getDataPath("images/logo_256.png")));
splash->show();
QTranslator qtTranslator; QTranslator qtTranslator;
QTranslator myTranslator; QTranslator myTranslator;
@ -74,9 +69,6 @@ int main(int argc, char** argv)
window = new MainWindow(); window = new MainWindow();
window->show(); window->show();
//window->showMaximized(); //window->showMaximized();
splash->finish(window);
delete splash;
result = app.exec(); result = app.exec();

View file

@ -25,7 +25,6 @@ HEADERS += \
inputcamera.h \ inputcamera.h \
inputboolean.h \ inputboolean.h \
formwater.h \ formwater.h \
formtextures.h \
formrender.h \ formrender.h \
formclouds.h \ formclouds.h \
formatmosphere.h \ formatmosphere.h \
@ -74,7 +73,6 @@ SOURCES += \
inputcamera.cpp \ inputcamera.cpp \
inputboolean.cpp \ inputboolean.cpp \
formwater.cpp \ formwater.cpp \
formtextures.cpp \
formrender.cpp \ formrender.cpp \
formclouds.cpp \ formclouds.cpp \
formatmosphere.cpp \ formatmosphere.cpp \

View file

@ -1,171 +0,0 @@
#include "formtextures.h"
#include "DesktopScenery.h"
#include "BasePreview.h"
#include "tools.h"
#include "CameraDefinition.h"
#include "TexturesDefinition.h"
#include "TextureLayerDefinition.h"
#include "SoftwareRenderer.h"
#include "TerrainRenderer.h"
/**************** Previews ****************/
class PreviewTexturesCoverage : public BasePreview
{
public:
PreviewTexturesCoverage(QWidget* parent, TextureLayerDefinition* layer) : BasePreview(parent)
{
_renderer = new SoftwareRenderer();
_renderer->render_quality = 3;
_original_layer = layer;
addOsd(QString("geolocation"));
configScaling(20.0, 500.0, 20.0, 50.0);
configScrolling(-1000.0, 1000.0, 0.0, -1000.0, 1000.0, 0.0);
}
~PreviewTexturesCoverage()
{
delete _renderer;
}
protected:
Color getColor(double x, double y)
{
Vector3 location;
Color result;
location.x = x;
location.y = _renderer->getTerrainRenderer()->getHeight(x, y, 1);
location.z = y;
//result.r = result.g = result.b = texturesGetLayerCoverage(_preview_layer, _renderer, location, this->scaling);
return result;
}
void updateData()
{
TexturesDefinition* textures = _renderer->getScenery()->getTextures();
textures->clear();
textures->addLayer();
_original_layer->copy(textures->getLayer(0));
_renderer->prepare();
}
private:
SoftwareRenderer* _renderer;
TextureLayerDefinition* _original_layer;
};
class PreviewTexturesColor : public BasePreview
{
public:
PreviewTexturesColor(QWidget* parent, TextureLayerDefinition* layer) : BasePreview(parent)
{
_original_layer = layer;
_renderer = new SoftwareRenderer();
_renderer->render_quality = 3;
_renderer->render_camera->setLocation(Vector3(0.0, 20.0, 0.0));
configScaling(0.01, 1.0, 0.01, 0.1);
configScrolling(-1000.0, 1000.0, 0.0, -1000.0, 1000.0, 0.0);
}
~PreviewTexturesColor()
{
delete _renderer;
}
protected:
Color getColor(double x, double y)
{
Vector3 location;
location.x = x;
location.y = 0.0;
location.z = y;
//return texturesGetLayerColor(_preview_layer, _renderer, location, this->scaling);
return COLOR_BLACK;
}
void updateData()
{
TexturesDefinition* textures = _renderer->getScenery()->getTextures();
textures->clear();
textures->addLayer();
_original_layer->copy(textures->getLayer(0));
_renderer->prepare();
}
private:
SoftwareRenderer* _renderer;
TextureLayerDefinition* _original_layer;
};
/**************** Form ****************/
FormTextures::FormTextures(QWidget *parent) :
BaseFormLayer(parent)
{
addAutoPreset(tr("Rock"));
addAutoPreset(tr("Grass"));
addAutoPreset(tr("Sand"));
addAutoPreset(tr("Snow"));
_definition = new TexturesDefinition(NULL);
_layer = new TextureLayerDefinition(NULL);
_previewCoverage = new PreviewTexturesCoverage(this, _layer);
_previewColor = new PreviewTexturesColor(this, _layer);
addPreview(_previewCoverage, tr("Coverage preview"));
addPreview(_previewColor, tr("Lighted sample"));
addInputDouble(tr("Displacement height"), &_layer->displacement_height, 0.0, 0.1, 0.001, 0.01);
addInputDouble(tr("Displacement scaling"), &_layer->displacement_scaling, 0.003, 0.3, 0.003, 0.03);
addInputMaterial(tr("Material"), _layer->material);
/*addInputCurve(tr("Coverage by altitude"), _layer->terrain_zone->value_by_height, -20.0, 20.0, 0.0, 1.0, tr("Terrain altitude"), tr("Texture coverage"));
addInputCurve(tr("Coverage by slope"), _layer->terrain_zone->value_by_slope, 0.0, 5.0, 0.0, 1.0, tr("Terrain slope"), tr("Texture coverage"));*/
/*addInputDouble(tr("Amplitude for slope coverage"), &_layer->slope_range, 0.001, 0.1, 0.001, 0.01);
addInputDouble(tr("Layer thickness"), &_layer->thickness, 0.0, 0.1, 0.001, 0.01);
addInputDouble(tr("Transparency thickness"), &_layer->thickness_transparency, 0.0, 0.1, 0.001, 0.01);*/
setLayers(_definition);
}
FormTextures::~FormTextures()
{
delete _definition;
delete _layer;
}
void FormTextures::revertConfig()
{
DesktopScenery::getCurrent()->getTextures(_definition);
BaseFormLayer::revertConfig();
}
void FormTextures::applyConfig()
{
BaseFormLayer::applyConfig();
DesktopScenery::getCurrent()->setTextures(_definition);
}
void FormTextures::layerReadCurrentFrom(void* layer_definition)
{
((TextureLayerDefinition*)layer_definition)->copy(_layer);
}
void FormTextures::layerWriteCurrentTo(void* layer_definition)
{
_layer->copy((TextureLayerDefinition*)layer_definition);
}
void FormTextures::autoPresetSelected(int preset)
{
_layer->applyPreset((TextureLayerDefinition::TextureLayerPreset)preset);
BaseForm::autoPresetSelected(preset);
}

View file

@ -1,34 +0,0 @@
#ifndef _PAYSAGES_QT_FORMTEXTURES_H_
#define _PAYSAGES_QT_FORMTEXTURES_H_
#include "desktop_global.h"
#include "baseformlayer.h"
class QWidget;
class FormTextures : public BaseFormLayer
{
Q_OBJECT
public:
explicit FormTextures(QWidget *parent = 0);
~FormTextures();
public slots:
virtual void revertConfig();
virtual void applyConfig();
protected:
virtual void layerReadCurrentFrom(void* layer_definition);
virtual void layerWriteCurrentTo(void* layer_definition);
virtual void autoPresetSelected(int preset);
private:
TexturesDefinition* _definition;
TextureLayerDefinition* _layer;
BasePreview* _previewCoverage;
BasePreview* _previewColor;
};
#endif

View file

@ -8,6 +8,7 @@
#include "common/freeformhelper.h" #include "common/freeformhelper.h"
#include "tools.h" #include "tools.h"
#include "DesktopScenery.h" #include "DesktopScenery.h"
#include "TexturesDefinition.h"
#include "TerrainDefinition.h" #include "TerrainDefinition.h"
#include "TerrainHeightMap.h" #include "TerrainHeightMap.h"
@ -70,8 +71,7 @@ void MainTerrainForm::refreshFromLocalData()
void MainTerrainForm::refreshFromFellowData() void MainTerrainForm::refreshFromFellowData()
{ {
//double disp = texturesGetMaximalDisplacement(RenderingScenery::getCurrent()->getTextures()); double disp = DesktopScenery::getCurrent()->getTextures()->getMaximalDisplacement();
double disp = -1000.0;
if (disp == 0.0) if (disp == 0.0)
{ {
@ -79,7 +79,9 @@ void MainTerrainForm::refreshFromFellowData()
} }
else else
{ {
ui->label_info_textures->setText(tr("Maximal displacement : %1% of total height").arg(100.0 * disp / _terrain->height, 0, 'f', 1)); HeightInfo info = DesktopScenery::getCurrent()->getTerrain()->getHeightInfo();
double terrain_height = info.max_height - info.min_height;
ui->label_info_textures->setText(tr("Maximal displacement : %1% of total height").arg(100.0 * disp / terrain_height, 0, 'f', 1));
} }
} }

View file

@ -0,0 +1,103 @@
#include "TerrainRayWalker.h"
#include "SoftwareRenderer.h"
#include "Scenery.h"
#include "TerrainDefinition.h"
#include "TexturesDefinition.h"
#include "TerrainRenderer.h"
#include "TexturesRenderer.h"
TerrainRayWalker::TerrainRayWalker(SoftwareRenderer* renderer):
renderer(renderer)
{
}
void TerrainRayWalker::update()
{
TerrainDefinition* terrain = renderer->getScenery()->getTerrain();
HeightInfo info = terrain->getHeightInfo();
TexturesDefinition* textures = renderer->getScenery()->getTextures();
double disp = textures->getMaximalDisplacement();
ymin = info.min_height - disp;
ymax = info.max_height + disp;
ydispmin = -disp;
ydispmax = disp;
minstep = 0.01 * terrain->scaling / (double)renderer->render_quality;
maxstep = 1.0 * terrain->scaling;
}
bool TerrainRayWalker::startWalking(Vector3 start, const Vector3 &direction, double escaping_factor, double max_length, TerrainHitResult &result)
{
TerrainRenderer* terrain_renderer = renderer->getTerrainRenderer();
TexturesRenderer* textures_renderer = renderer->getTexturesRenderer();
TerrainRenderer::TerrainResult terrain_result;
Vector3 end, displaced;
bool hit;
double diff;
double step_length = minstep;
double walked_length = 0.0;
do
{
// Perform a step
end = start.add(direction.scale(step_length));
// Get the terrain info at end (without textures displacement)
terrain_result = terrain_renderer->getResult(end.x, end.z, true, false);
diff = end.y - terrain_result.location.y;
// If we are very under the terrain, consider a hit
if (diff < ydispmin)
{
hit = true;
}
// If we are close enough to the terrain, apply displacement
else if (diff < ydispmax)
{
displaced = textures_renderer->displaceTerrain(terrain_result);
diff = end.y - displaced.y;
hit = (diff < 0.0);
}
if (hit)
{
// Refine the hit with dichotomy at high quality
/*if (renderer->render_quality > 7)
{
end = refineHit(start, end, step_length);
}*/
// Find an escape
/*if (escaping_factor != 0.0)
{
result.escape_length = findEscape(end, walked_length, escaping_factor, max_length);
}*/
result.hit_location = end;
}
else
{
// Prepare next step
start = end;
walked_length += step_length;
step_length = diff / (double)renderer->render_quality;
if (step_length < minstep)
{
step_length = minstep;
}
else if (step_length > maxstep)
{
step_length = maxstep;
}
}
} while (not hit and start.y < ymax and walked_length < max_length);
return hit;
}

View file

@ -0,0 +1,59 @@
#ifndef TERRAINRAYWALKER_H
#define TERRAINRAYWALKER_H
#include "software_global.h"
#include "Vector3.h"
namespace paysages {
namespace software {
/*!
* \brief Ray walker to find intersections with terrain.
*
* This walker can be used to find a hard intersection between
* a ray and the terrain (e.g. for raytracing), or a soft intersection
* (e.g. for shadows).
*/
class SOFTWARESHARED_EXPORT TerrainRayWalker
{
public:
typedef struct {
Vector3 hit_location; // Location of the hit
double escape_length; // Length walked before terrain was escaped after hit (0.0 if no escape)
} TerrainHitResult;
public:
TerrainRayWalker(SoftwareRenderer* renderer);
/*!
* \brief Update the walker internal data, from the renderer and scenery.
*/
void update();
/*!
* \brief Start the walking process to find intersection
*
* \param start Point of origin of the ray
* \param direction Ray direction (normalized vector)
* \param escaping_factor Factor used 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
* \return true if there was a hit
*/
bool startWalking(Vector3 start, const Vector3 &direction, double escaping_factor, double max_length, TerrainHitResult &result);
private:
SoftwareRenderer* renderer;
double ymin;
double ymax;
double ydispmin;
double ydispmax;
double minstep;
double maxstep;
};
}
}
#endif // TERRAINRAYWALKER_H

View file

@ -5,18 +5,22 @@
#include "TerrainDefinition.h" #include "TerrainDefinition.h"
#include "TexturesRenderer.h" #include "TexturesRenderer.h"
#include "LightComponent.h" #include "LightComponent.h"
#include "TerrainRayWalker.h"
TerrainRenderer::TerrainRenderer(SoftwareRenderer* parent): TerrainRenderer::TerrainRenderer(SoftwareRenderer* parent):
parent(parent) parent(parent)
{ {
walker = new TerrainRayWalker(parent);
} }
TerrainRenderer::~TerrainRenderer() TerrainRenderer::~TerrainRenderer()
{ {
delete walker;
} }
void TerrainRenderer::update() void TerrainRenderer::update()
{ {
walker->update();
} }
double TerrainRenderer::getHeight(double x, double z, int with_painting) double TerrainRenderer::getHeight(double x, double z, int with_painting)
@ -130,59 +134,17 @@ Color TerrainRenderer::getFinalColor(const Vector3 &location, double)
RayCastingResult TerrainRenderer::castRay(const Vector3 &start, const Vector3 &direction) RayCastingResult TerrainRenderer::castRay(const Vector3 &start, const Vector3 &direction)
{ {
RayCastingResult result; RayCastingResult result;
TerrainDefinition* definition = parent->getScenery()->getTerrain(); TerrainRayWalker::TerrainHitResult walk_result;
Vector3 inc_vector, direction_norm, cursor; if (walker->startWalking(start, direction.normalize(), 0.0, 200.0, walk_result))
double inc_value, inc_base, inc_factor, height, diff, lastdiff, length;
cursor = start;
direction_norm = direction.normalize();
inc_factor = (double)parent->render_quality;
inc_base = 1.0;
inc_value = inc_base / inc_factor;
lastdiff = start.y - getHeight(start.x, start.z, 1);
length = 0.0;
do
{ {
inc_vector = direction_norm.scale(inc_value); result.hit = true;
length += inc_vector.getNorm(); result.hit_location = walk_result.hit_location;
cursor = cursor.add(inc_vector); result.hit_color = getFinalColor(walk_result.hit_location, parent->getPrecision(walk_result.hit_location));
height = getHeight(cursor.x, cursor.z, 1); }
diff = cursor.y - height; else
if (diff < 0.0) {
{ result.hit = false;
if (fabs(diff - lastdiff) > 0.00001)
{
cursor = cursor.add(inc_vector.scale(-diff / (diff - lastdiff)));
cursor.y = getHeight(cursor.x, cursor.z, 1);
}
else
{
cursor.y = height;
}
result.hit = 1;
result.hit_location = cursor;
result.hit_color = getFinalColor(cursor, parent->getPrecision(result.hit_location));
return result;
}
if (diff < inc_base / inc_factor)
{
inc_value = inc_base / inc_factor;
}
else if (diff > inc_base)
{
inc_value = inc_base;
}
else
{
inc_value = diff;
}
lastdiff = diff;
} }
while (length < 50.0 && cursor.y <= definition->_max_height);
result.hit = 0;
return result; return result;
} }

View file

@ -35,6 +35,7 @@ public:
private: private:
SoftwareRenderer* parent; SoftwareRenderer* parent;
TerrainRayWalker* walker;
}; };
} }

View file

@ -36,7 +36,8 @@ SOURCES += SoftwareRenderer.cpp \
WaterRenderer.cpp \ WaterRenderer.cpp \
RenderArea.cpp \ RenderArea.cpp \
RayCastingManager.cpp \ RayCastingManager.cpp \
NightSky.cpp NightSky.cpp \
TerrainRayWalker.cpp
HEADERS += SoftwareRenderer.h\ HEADERS += SoftwareRenderer.h\
software_global.h \ software_global.h \
@ -62,7 +63,8 @@ HEADERS += SoftwareRenderer.h\
WaterRenderer.h \ WaterRenderer.h \
RenderArea.h \ RenderArea.h \
RayCastingManager.h \ RayCastingManager.h \
NightSky.h NightSky.h \
TerrainRayWalker.h
unix:!symbian { unix:!symbian {
maemo5 { maemo5 {

View file

@ -42,6 +42,8 @@ namespace software {
class LightComponent; class LightComponent;
class NightSky; class NightSky;
class TerrainRayWalker;
} }
} }