paysages : Terrain canvas - Added bicubic interpolation and integration mask.

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@393 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2012-07-18 15:04:23 +00:00 committed by ThunderK
parent 818b8b7b86
commit 2d2535deae
4 changed files with 73 additions and 18 deletions

View file

@ -13,8 +13,8 @@ FormTerrainCanvas::FormTerrainCanvas(QWidget *parent, Layers* layers):
addInputNoise(tr("Detail noise"), _definition->detail_noise); addInputNoise(tr("Detail noise"), _definition->detail_noise);
addInputDouble(tr("Detail noise height"), &_definition->detail_height_factor, 0.0, 20.0, 0.1, 1.0); addInputDouble(tr("Detail noise height"), &_definition->detail_height_factor, 0.0, 20.0, 0.1, 1.0);
addInputDouble(tr("Detail noise scaling"), &_definition->detail_scaling, 0.0, 20.0, 0.1, 1.0); addInputDouble(tr("Detail noise scaling"), &_definition->detail_scaling, 0.0, 20.0, 0.1, 1.0);
addInputEnum(tr("Mask shape"), &_definition->mask_mode, QStringList(tr("Square")) << tr("Circle")); addInputEnum(tr("Mask shape"), &_definition->mask.mode, QStringList(tr("Square")) << tr("Circle"));
addInputDouble(tr("Mask smoothing"), &_definition->mask_smoothing, 0.0, 1.0, 0.01, 0.1); addInputDouble(tr("Mask smoothing"), &_definition->mask.smoothing, 0.0, 1.0, 0.01, 0.1);
revertConfig(); revertConfig();
} }

View file

@ -1,4 +1,5 @@
#include "heightmap.h" #include "heightmap.h"
#include "tools.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -73,8 +74,26 @@ void heightmapChangeResolution(HeightMap* heightmap, int resolution_x, int resol
double heightmapGetValue(HeightMap* heightmap, double x, double z) double heightmapGetValue(HeightMap* heightmap, double x, double z)
{ {
// TODO Bicubic interpolation int xmax = heightmap->resolution_x - 1;
return heightmap->data[lround(z * (heightmap->resolution_z - 1)) * heightmap->resolution_x + lround(x * (heightmap->resolution_x - 1))]; int zmax = heightmap->resolution_z - 1;
int xlow = floor(x * xmax);
int zlow = floor(z * zmax);
double stencil[16];
int ix, iz, cx, cz;
for (ix = xlow - 1; ix <= xlow + 2; ix++)
{
for (iz = zlow - 1; iz <= zlow + 2; iz++)
{
cx = ix < 0 ? 0 : ix;
cx = cx > xmax ? xmax : cx;
cz = iz < 0 ? 0 : iz;
cz = cz > zmax ? zmax : cz;
stencil[(iz - (zlow - 1)) * 4 + ix - (xlow - 1)] = heightmap->data[cz * heightmap->resolution_x + cx];
}
}
return toolsBicubicInterpolate(stencil, x * xmax - (double)xlow, z * zmax - (double)zlow);
} }
void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value) void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double value)
@ -82,7 +101,7 @@ void heightmapBrushElevation(HeightMap* heightmap, HeightMapBrush* brush, double
int x, z; int x, z;
double dx, dz, distance; double dx, dz, distance;
// TODO Limit to brush radius /* TODO Limit to brush radius */
for (x = 0; x < heightmap->resolution_x; x++) for (x = 0; x < heightmap->resolution_x; x++)
{ {

View file

@ -19,8 +19,8 @@ TerrainCanvas* terrainCanvasCreate()
result->detail_noise = noiseCreateGenerator(); result->detail_noise = noiseCreateGenerator();
result->detail_height_factor = 0.1; result->detail_height_factor = 0.1;
result->detail_scaling = 1.0; result->detail_scaling = 1.0;
result->mask_mode = TERRAINCANVAS_MASKMODE_SQUARE; result->mask.mode = INTEGRATIONMASK_MODE_CIRCLE;
result->mask_smoothing = 0.0; result->mask.smoothing = 0.1;
return result; return result;
} }
@ -41,8 +41,7 @@ void terrainCanvasCopy(TerrainCanvas* source, TerrainCanvas* destination)
noiseCopy(source->detail_noise, destination->detail_noise); noiseCopy(source->detail_noise, destination->detail_noise);
destination->detail_height_factor = source->detail_height_factor; destination->detail_height_factor = source->detail_height_factor;
destination->detail_scaling = source->detail_scaling; destination->detail_scaling = source->detail_scaling;
destination->mask_mode = source->mask_mode; destination->mask = source->mask;
destination->mask_smoothing = source->mask_smoothing;
} }
void terrainCanvasValidate(TerrainCanvas* canvas) void terrainCanvasValidate(TerrainCanvas* canvas)
@ -82,8 +81,8 @@ void terrainCanvasSave(PackStream* stream, TerrainCanvas* canvas)
noiseSaveGenerator(stream, canvas->detail_noise); noiseSaveGenerator(stream, canvas->detail_noise);
packWriteDouble(stream, &canvas->detail_height_factor); packWriteDouble(stream, &canvas->detail_height_factor);
packWriteDouble(stream, &canvas->detail_scaling); packWriteDouble(stream, &canvas->detail_scaling);
packWriteInt(stream, &canvas->mask_mode); packWriteInt(stream, &canvas->mask.mode);
packWriteDouble(stream, &canvas->mask_smoothing); packWriteDouble(stream, &canvas->mask.smoothing);
} }
void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas) void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas)
@ -99,8 +98,8 @@ void terrainCanvasLoad(PackStream* stream, TerrainCanvas* canvas)
noiseLoadGenerator(stream, canvas->detail_noise); noiseLoadGenerator(stream, canvas->detail_noise);
packReadDouble(stream, &canvas->detail_height_factor); packReadDouble(stream, &canvas->detail_height_factor);
packReadDouble(stream, &canvas->detail_scaling); packReadDouble(stream, &canvas->detail_scaling);
packReadInt(stream, &canvas->mask_mode); packReadInt(stream, &canvas->mask.mode);
packReadDouble(stream, &canvas->mask_smoothing); packReadDouble(stream, &canvas->mask.smoothing);
} }
void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked) void terrainCanvasRevertToTerrain(TerrainCanvas* canvas, TerrainDefinition* terrain, int only_masked)
@ -114,7 +113,39 @@ Vector3 terrainCanvasApply(TerrainCanvas* canvas, Vector3 location)
location.x <= canvas->area.location_x + canvas->area.size_x && location.x <= canvas->area.location_x + canvas->area.size_x &&
location.z <= canvas->area.location_z + canvas->area.size_z) location.z <= canvas->area.location_z + canvas->area.size_z)
{ {
location.y = heightmapGetValue(&canvas->height_map, (location.x - canvas->area.location_x) / canvas->area.size_x, (location.z - canvas->area.location_z) / canvas->area.size_z); double inside_x, inside_z;
double height, distance;
/* Get height map displacement */
inside_x = (location.x - canvas->area.location_x) / canvas->area.size_x;
inside_z = (location.z - canvas->area.location_z) / canvas->area.size_z;
height = heightmapGetValue(&canvas->height_map, inside_x, inside_z);
/* TODO Apply detail noise */
/* Apply integration mask */
inside_x = (inside_x - 0.5) * 2.0;
inside_z = (inside_z - 0.5) * 2.0;
if (canvas->mask.mode == INTEGRATIONMASK_MODE_SQUARE)
{
inside_x = fabs(inside_x);
inside_z = fabs(inside_z);
distance = inside_x > inside_z ? inside_x : inside_z;
}
else
{
distance = sqrt(inside_x * inside_x + inside_z * inside_z);
}
if (distance <= 1.0 - canvas->mask.smoothing)
{
location.y = height;
}
else
{
double influence = (1.0 - distance) / canvas->mask.smoothing;
location.y = influence * height + (1.0 - influence) * location.y;
}
} }
return location; return location;
} }

View file

@ -22,8 +22,14 @@ typedef struct
double size_z; double size_z;
} GeoArea; } GeoArea;
#define TERRAINCANVAS_MASKMODE_SQUARE 0 typedef struct
#define TERRAINCANVAS_MASKMODE_CIRCLE 1 {
int mode;
double smoothing;
} IntegrationMask;
#define INTEGRATIONMASK_MODE_SQUARE 0
#define INTEGRATIONMASK_MODE_CIRCLE 1
typedef struct typedef struct
{ {
@ -34,8 +40,7 @@ typedef struct
NoiseGenerator* detail_noise; NoiseGenerator* detail_noise;
double detail_height_factor; double detail_height_factor;
double detail_scaling; double detail_scaling;
int mask_mode; IntegrationMask mask;
double mask_smoothing;
} TerrainCanvas; } TerrainCanvas;
TerrainCanvas* terrainCanvasCreate(); TerrainCanvas* terrainCanvasCreate();