WIP on textures refactoring

This commit is contained in:
Michaël Lemaire 2016-02-07 22:54:58 +01:00
parent b3787ed7ea
commit 24b73b1504
22 changed files with 266 additions and 590 deletions

View file

@ -7,7 +7,6 @@
#include "CameraDefinition.h"
#include "CloudsDefinition.h"
#include "TerrainDefinition.h"
#include "TexturesDefinition.h"
#include "VegetationDefinition.h"
#include "WaterDefinition.h"
#include "DiffManager.h"
@ -24,7 +23,6 @@ Scenery::Scenery() : DefinitionNode(NULL, "scenery", "scenery") {
camera = new CameraDefinition(this);
clouds = new CloudsDefinition(this);
terrain = new TerrainDefinition(this);
textures = new TexturesDefinition(this);
water = new WaterDefinition(this);
vegetation = new VegetationDefinition(this);
}
@ -135,7 +133,6 @@ const Scenery *Scenery::getScenery() const {
void Scenery::autoPreset(RandomGenerator &random) {
terrain->applyPreset(TerrainDefinition::TERRAIN_PRESET_STANDARD, random);
textures->applyPreset(TexturesDefinition::TEXTURES_PRESET_FULL, random);
atmosphere->applyPreset(AtmosphereDefinition::ATMOSPHERE_PRESET_CLEAR_DAY, random);
water->applyPreset(WaterDefinition::WATER_PRESET_LAKE, random);
clouds->applyPreset(CloudsDefinition::CLOUDS_PRESET_PARTLY_CLOUDY, random);
@ -187,14 +184,6 @@ void Scenery::getTerrain(TerrainDefinition *terrain) {
this->terrain->copy(terrain);
}
void Scenery::setTextures(TexturesDefinition *textures) {
textures->copy(this->textures);
}
void Scenery::getTextures(TexturesDefinition *textures) {
this->textures->copy(textures);
}
void Scenery::setVegetation(VegetationDefinition *vegetation) {
vegetation->copy(this->vegetation);
}
@ -213,7 +202,7 @@ void Scenery::getWater(WaterDefinition *water) {
void Scenery::keepCameraAboveGround(CameraDefinition *camera) {
Vector3 camera_location = camera->getLocation();
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, true, true) + 1.0;
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, true, true) + terrain->getMaximalDisplacement() + 0.5;
double water_height = 0.5;
if (camera_location.y < water_height || camera_location.y < terrain_height) {
double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y;

View file

@ -95,12 +95,6 @@ class DEFINITIONSHARED_EXPORT Scenery : public DefinitionNode {
}
void getTerrain(TerrainDefinition *terrain);
void setTextures(TexturesDefinition *textures);
inline TexturesDefinition *getTextures() const {
return textures;
}
void getTextures(TexturesDefinition *textures);
void setVegetation(VegetationDefinition *Vegetation);
inline VegetationDefinition *getVegetation() const {
return vegetation;
@ -120,7 +114,6 @@ class DEFINITIONSHARED_EXPORT Scenery : public DefinitionNode {
CameraDefinition *camera;
CloudsDefinition *clouds;
TerrainDefinition *terrain;
TexturesDefinition *textures;
VegetationDefinition *vegetation;
WaterDefinition *water;
};

View file

@ -1,12 +1,26 @@
#include "TerrainDefinition.h"
#include <cmath>
#include "Layers.h"
#include "TextureLayerDefinition.h"
#include "TerrainHeightMap.h"
#include "NoiseGenerator.h"
#include "PackStream.h"
#include "FloatNode.h"
#include "NoiseNode.h"
#include "MaterialNode.h"
#include "FractalNoise.h"
#include "SurfaceMaterial.h"
#include "Color.h"
#include "Zone.h"
static DefinitionNode *_newTerrainDisplacement(Layers *parent, const string &name) {
return new TextureLayerDefinition(parent, name);
}
static DefinitionNode *_newTerrainColor(Layers *parent, const string &name) {
return new TextureLayerDefinition(parent, name);
}
TerrainDefinition::TerrainDefinition(DefinitionNode *parent) : DefinitionNode(parent, "terrain", "terrain") {
shadow_smoothing = 0.0;
@ -15,8 +29,13 @@ TerrainDefinition::TerrainDefinition(DefinitionNode *parent) : DefinitionNode(pa
has_painting = false;
addChild(height_map);
default_material = new MaterialNode(this, "default_material");
water_height = new FloatNode(this, "water_height");
height_noise = new NoiseNode(this, "height_noise");
displacements = new Layers(this, "displacements", _newTerrainDisplacement);
materials = new Layers(this, "materials", _newTerrainColor);
}
TerrainDefinition::~TerrainDefinition() {
@ -27,7 +46,11 @@ void TerrainDefinition::validate() {
// Get base noise range
height_noise->getGenerator()->estimateRange(&_min_height, &_max_height, 0.1);
// TODO Alter limits with heightmap min/max, and displacement textures
// TODO Alter limits with heightmap min/max
double max_displacement = getMaximalDisplacement();
_min_height -= max_displacement;
_max_height += max_displacement;
has_painting = height_map->hasPainting();
}
@ -60,7 +83,7 @@ double TerrainDefinition::getGridHeight(int x, int z, bool with_painting) {
double h;
if (!with_painting || !has_painting || !height_map->getGridValue(x, z, &h)) {
h = height_noise->getGenerator()->get2d(0.1, to_double(x), to_double(z));
h = height_noise->getGenerator()->get2d(1.0, to_double(x), to_double(z));
}
return h;
@ -70,7 +93,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, bool with_pa
double h;
if (!with_painting || !has_painting || !height_map->getInterpolatedValue(x, z, &h)) {
h = height_noise->getGenerator()->get2d(0.1, x, z);
h = height_noise->getGenerator()->get2d(1.0, x, z);
}
return (water_offset ? (h + getWaterOffset()) : h);
@ -81,6 +104,17 @@ double TerrainDefinition::getWaterOffset() const {
return -water_height->getValue() * height_power;
}
double TerrainDefinition::getMaximalDisplacement() {
double result = 0.0;
int n = displacements->getLayerCount();
for (int i = 0; i < n; i++) {
if (auto layer = dynamic_cast<TextureLayerDefinition *>(displacements->getLayer(i))) {
result += layer->getMaximalDisplacement();
}
}
return result;
}
HeightInfo TerrainDefinition::getHeightInfo() {
HeightInfo result;
@ -96,11 +130,55 @@ unsigned long TerrainDefinition::getMemoryStats() {
}
void TerrainDefinition::applyPreset(TerrainPreset preset, RandomGenerator &random) {
default_material->setSurfaceMaterial(SurfaceMaterial(Color(0.6, 0.55, 0.57, 1.0)));
displacements->clear();
materials->clear();
switch (preset) {
case TERRAIN_PRESET_STANDARD:
height_noise->randomize(random);
height_noise->setConfig(400.0, 0.1, 0.5, 1.02);
shadow_smoothing = 0.03;
TextureLayerDefinition mountain(NULL, "mountain");
mountain.propTerrainZone()->addHeightRangeQuick(1.0, 0.4, 0.7, 0.87, 0.95);
mountain.propDisplacementNoise()->setConfig(4.0, 0.15, 0.5, 0.8);
displacements->addLayer(mountain);
TextureLayerDefinition mud(NULL, "mud");
mud.propTerrainZone()->addHeightRangeQuick(1.0, 0.4, 0.7, 0.87, 0.95);
mud.propMaterial()->propBump()->setConfig(0.05, 0.1, 0.3);
mud.propMaterial()->setSurfaceMaterial(Color(0.015, 0.014, 0.014), 0.001, 4.0);
materials->addLayer(mud);
TextureLayerDefinition rock(NULL, "rock");
rock.propTerrainZone()->addHeightRangeQuick(1.0, 0.6, 0.7, 0.87, 0.95);
rock.propMaterial()->propBump()->setConfig(0.02, 0.04);
rock.propMaterial()->setSurfaceMaterial(Color(0.6, 0.55, 0.57), 0.002, 6.0);
materials->addLayer(rock);
TextureLayerDefinition grass(NULL, "grass");
grass.propTerrainZone()->addHeightRangeQuick(1.0, 0.45, 0.5, 0.7, 0.9);
grass.propTerrainZone()->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.4);
grass.propMaterial()->propBump()->setConfig(2.0, 0.05);
grass.propMaterial()->setSurfaceMaterial(Color(0.12, 0.19, 0.035), 0.001, 4.0);
materials->addLayer(grass);
TextureLayerDefinition sand(NULL, "sand");
sand.propTerrainZone()->addHeightRangeQuick(1.0, 0.495, 0.505, 0.56, 0.63);
sand.propTerrainZone()->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.3);
sand.propMaterial()->propBump()->setConfig(0.004, 0.08);
sand.propMaterial()->setSurfaceMaterial(Color(1.2, 1.1, 0.9), 0.003, 1.0);
materials->addLayer(sand);
TextureLayerDefinition snow(NULL, "snow");
snow.propTerrainZone()->addHeightRangeQuick(1.0, 0.87, 0.95, 10.0, 100.0);
snow.propTerrainZone()->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.1, 1.0);
snow.propMaterial()->propBump()->setConfig(0.01, 0.03);
snow.propMaterial()->setSurfaceMaterial(Color(5.0, 5.0, 5.0), 0.01, 0.6);
materials->addLayer(snow);
break;
}

View file

@ -25,16 +25,26 @@ class DEFINITIONSHARED_EXPORT TerrainDefinition : public DefinitionNode {
virtual void copy(DefinitionNode *destination) const override;
virtual void validate() override;
inline MaterialNode *propDefaultMaterial() const {
return default_material;
}
inline FloatNode *propWaterHeight() const {
return water_height;
}
inline NoiseNode *propHeightNoise() const {
return height_noise;
}
inline Layers *propDisplacements() const {
return displacements;
}
inline Layers *propMaterials() const {
return materials;
}
double getGridHeight(int x, int z, bool with_painting);
double getInterpolatedHeight(double x, double z, bool with_painting, bool water_offset = true);
double getWaterOffset() const;
double getMaximalDisplacement();
unsigned long getMemoryStats();
HeightInfo getHeightInfo();
@ -52,8 +62,11 @@ class DEFINITIONSHARED_EXPORT TerrainDefinition : public DefinitionNode {
double _max_height;
private:
MaterialNode *default_material;
FloatNode *water_height;
NoiseNode *height_noise;
Layers *displacements;
Layers *materials;
};
}
}

View file

@ -9,29 +9,24 @@
#include "Color.h"
#include "FractalNoise.h"
#include "NoiseNode.h"
#include "MaterialNode.h"
TextureLayerDefinition::TextureLayerDefinition(DefinitionNode *parent, const string &name)
: DefinitionNode(parent, name, "texturelayer") {
terrain_zone = new Zone;
material = new SurfaceMaterial;
material = new MaterialNode(this, "material");
displacement_noise = new NoiseNode(this, "displacement");
displacement_noise->setConfig(0.0);
detail_noise = new NoiseNode(this, "detail");
detail_noise->setConfig(0.01);
}
TextureLayerDefinition::~TextureLayerDefinition() {
delete terrain_zone;
delete material;
}
void TextureLayerDefinition::validate() {
DefinitionNode::validate();
material->validate();
// Update zone height range
if (auto scenery = getScenery()) {
TerrainDefinition *terrain = scenery->getTerrain();
@ -45,8 +40,6 @@ void TextureLayerDefinition::copy(DefinitionNode *destination) const {
if (auto tex_destination = dynamic_cast<TextureLayerDefinition *>(destination)) {
terrain_zone->copy(tex_destination->terrain_zone);
*tex_destination->material = *material;
}
}
@ -54,68 +47,12 @@ void TextureLayerDefinition::save(PackStream *stream) const {
DefinitionNode::save(stream);
terrain_zone->save(stream);
material->save(stream);
}
void TextureLayerDefinition::load(PackStream *stream) {
DefinitionNode::load(stream);
terrain_zone->load(stream);
material->load(stream);
}
void TextureLayerDefinition::applyPreset(TextureLayerPreset preset, RandomGenerator &random) {
displacement_noise->randomize(random);
detail_noise->randomize(random);
terrain_zone->clear();
switch (preset) {
case TEXTURES_LAYER_PRESET_MUD:
displacement_noise->setConfig(0.05, 0.1, 0.3);
detail_noise->setConfig(0.01, 0.03);
material->setColor(0.015, 0.014, 0.014, 1.0);
material->reflection = 0.003;
material->shininess = 4.0;
break;
case TEXTURES_LAYER_PRESET_ROCK:
terrain_zone->addHeightRangeQuick(1.0, 0.6, 0.7, 0.87, 0.95);
displacement_noise->setConfig(4.0, 0.15, 0.5, 0.8);
detail_noise->setConfig(0.02, 0.04);
material->setColor(0.6, 0.55, 0.57, 1.0);
material->reflection = 0.006;
material->shininess = 6.0;
break;
case TEXTURES_LAYER_PRESET_GRASS:
terrain_zone->addHeightRangeQuick(1.0, 0.45, 0.5, 0.7, 0.9);
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.4);
displacement_noise->setConfig(2.0, 0.05);
detail_noise->setConfig(0.01, 0.1);
material->setColor(0.12, 0.19, 0.035, 1.0);
material->reflection = 0.001;
material->shininess = 4.0;
break;
case TEXTURES_LAYER_PRESET_SAND:
terrain_zone->addHeightRangeQuick(1.0, 0.495, 0.505, 0.56, 0.63);
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.3);
displacement_noise->setConfig(0.04, 0.1, 0.5, 0.3);
detail_noise->setConfig(0.004, 0.08);
material->setColor(1.2, 1.1, 0.9, 1.0);
material->reflection = 0.008;
material->shininess = 1.0;
break;
case TEXTURES_LAYER_PRESET_SNOW:
terrain_zone->addHeightRangeQuick(1.0, 0.87, 0.95, 10.0, 100.0);
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.1, 1.0);
displacement_noise->setConfig(0.4, 0.07);
detail_noise->setConfig(0.01, 0.03);
material->setColor(5.0, 5.0, 5.0, 1.0);
material->reflection = 0.02;
material->shininess = 0.6;
break;
}
validate();
}
bool TextureLayerDefinition::hasDisplacement() const {

View file

@ -9,16 +9,6 @@ namespace paysages {
namespace definition {
class DEFINITIONSHARED_EXPORT TextureLayerDefinition : public DefinitionNode {
public:
typedef enum { TEXTURES_MERGE_FADE, TEXTURES_MERGE_DISSOLVE, TEXTURES_MERGE_DISPLACEMENT_VALUE } TextureMergeMode;
typedef enum {
TEXTURES_LAYER_PRESET_MUD,
TEXTURES_LAYER_PRESET_ROCK,
TEXTURES_LAYER_PRESET_GRASS,
TEXTURES_LAYER_PRESET_SAND,
TEXTURES_LAYER_PRESET_SNOW
} TextureLayerPreset;
public:
TextureLayerDefinition(DefinitionNode *parent, const string &name);
virtual ~TextureLayerDefinition();
@ -29,13 +19,14 @@ class DEFINITIONSHARED_EXPORT TextureLayerDefinition : public DefinitionNode {
virtual void copy(DefinitionNode *destination) const override;
virtual void validate() override;
void applyPreset(TextureLayerPreset preset, RandomGenerator &random = RandomGeneratorDefault);
inline Zone *propTerrainZone() const {
return terrain_zone;
}
inline NoiseNode *propDisplacementNoise() const {
return displacement_noise;
}
inline NoiseNode *propDetailNoise() const {
return detail_noise;
inline MaterialNode *propMaterial() const {
return material;
}
/**
@ -48,13 +39,10 @@ class DEFINITIONSHARED_EXPORT TextureLayerDefinition : public DefinitionNode {
*/
double getMaximalDisplacement() const;
public:
Zone *terrain_zone;
SurfaceMaterial *material;
private:
Zone *terrain_zone;
NoiseNode *displacement_noise;
NoiseNode *detail_noise;
MaterialNode *material;
};
}
}

View file

@ -1,62 +0,0 @@
#include "TexturesDefinition.h"
#include "TextureLayerDefinition.h"
static DefinitionNode *_layer_constructor(Layers *parent, const string &name) {
return new TextureLayerDefinition(parent, name);
}
TexturesDefinition::TexturesDefinition(DefinitionNode *parent) : Layers(parent, "textures", _layer_constructor) {
}
void TexturesDefinition::applyPreset(TexturesPreset preset, RandomGenerator &random) {
TextureLayerDefinition layer(NULL, "temp");
clear();
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_MUD, random);
layer.setName("Mud");
addLayer(layer);
if (preset == TEXTURES_PRESET_FULL) {
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_ROCK, random);
layer.setName("Ground");
addLayer(layer);
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_GRASS, random);
layer.setName("Grass");
addLayer(layer);
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_SAND, random);
layer.setName("Sand");
addLayer(layer);
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_SNOW, random);
layer.setName("Snow");
addLayer(layer);
} else if (preset == TEXTURES_PRESET_IRELAND) {
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_ROCK, random);
layer.setName("Ground");
addLayer(layer);
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_GRASS, random);
layer.setName("Grass");
addLayer(layer);
} else if (preset == TEXTURES_PRESET_ALPS) {
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_ROCK, random);
layer.setName("Ground");
addLayer(layer);
layer.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_SNOW, random);
layer.setName("Snow");
addLayer(layer);
}
}
double TexturesDefinition::getMaximalDisplacement() {
double result = 0.0;
int n = getLayerCount();
for (int i = 0; i < n; i++) {
result += getTextureLayer(i)->getMaximalDisplacement();
}
return result;
}

View file

@ -1,27 +0,0 @@
#ifndef TEXTURESDEFINITION_H
#define TEXTURESDEFINITION_H
#include "definition_global.h"
#include "Layers.h"
namespace paysages {
namespace definition {
class DEFINITIONSHARED_EXPORT TexturesDefinition : public Layers {
public:
TexturesDefinition(DefinitionNode *parent);
inline TextureLayerDefinition *getTextureLayer(int position) const {
return (TextureLayerDefinition *)getLayer(position);
}
typedef enum { TEXTURES_PRESET_FULL, TEXTURES_PRESET_IRELAND, TEXTURES_PRESET_ALPS } TexturesPreset;
void applyPreset(TexturesPreset preset, RandomGenerator &random = RandomGeneratorDefault);
double getMaximalDisplacement();
};
}
}
#endif // TEXTURESDEFINITION_H

View file

@ -35,7 +35,6 @@ class CloudLayerDefinition;
class AtmosphereDefinition;
class CelestialBodyDefinition;
class GodRaysDefinition;
class TexturesDefinition;
class TextureLayerDefinition;
class TerrainDefinition;
class TerrainHeightMap;

View file

@ -7,7 +7,6 @@
#include "AtmosphereDefinition.h"
#include "AtmosphereRenderer.h"
#include "AtmosphereResult.h"
#include "TexturesDefinition.h"
#include "GodRaysDefinition.h"
#include "TextureLayerDefinition.h"
#include "WaterDefinition.h"
@ -37,6 +36,7 @@
#include "RandomGenerator.h"
#include "NoiseFunctionSimplex.h"
#include "Zone.h"
#include "MaterialNode.h"
#include <cmath>
#include <sstream>
@ -111,11 +111,11 @@ static void testGroundShadowQuality() {
scenery.getWater()->transparency = 0.0;
scenery.getAtmosphere()->applyPreset(AtmosphereDefinition::ATMOSPHERE_PRESET_CLEAR_SUNSET, random);
scenery.getAtmosphere()->setDayTime(16, 45);
scenery.getTextures()->clear();
/*scenery.getTextures()->clear();
TextureLayerDefinition texture(NULL, "test");
texture.applyPreset(TextureLayerDefinition::TEXTURES_LAYER_PRESET_ROCK);
texture.terrain_zone->clear();
scenery.getTextures()->addLayer(texture);
texture.propTerrainZone()->clear();
scenery.getTextures()->addLayer(texture);*/
scenery.getCamera()->setLocation(Vector3(10.0, 10.0, -10.0));
scenery.getCamera()->setTarget(VECTOR_ZERO);
@ -398,22 +398,22 @@ static void testTextures() {
// TODO Customize terrain function
for (int i = 0; i < 5; i++) {
/*for (int i = 0; i < 5; i++) {
TextureLayerDefinition layer(NULL, "test");
layer.applyPreset(static_cast<TextureLayerDefinition::TextureLayerPreset>(i));
layer.terrain_zone->clear();
layer.propTerrainZone()->clear();
scenery.getTextures()->clear();
scenery.getTextures()->addLayer(layer);
startTestRender(&renderer, "texture", i * 2);
layer.propDetailNoise()->setConfig(0.0);
layer.propMaterial()->propBump()->setConfig(0.0);
scenery.getTextures()->clear();
scenery.getTextures()->addLayer(layer);
startTestRender(&renderer, "texture", i * 2 + 1);
}
}*/
for (int i = 0; i < 4; i++) {
scenery.getTextures()->applyPreset(static_cast<TexturesDefinition::TexturesPreset>(i));
/*scenery.getTextures()->applyPreset(static_cast<TexturesDefinition::TexturesPreset>(i));*/
startTestRender(&renderer, "texture_comp", i);
}
}

View file

@ -4,6 +4,8 @@
#include "LightComponent.h"
#include "Color.h"
#include "SurfaceMaterial.h"
#include "MaterialNode.h"
#include "FractalNoise.h"
LightStatus::LightStatus(LightingManager *manager, const Vector3 &location, const Vector3 &eye, bool filtered) {
this->safety_offset = -0.0000001;
@ -33,7 +35,7 @@ void LightStatus::pushComponent(LightComponent component) {
}
}
Color LightStatus::apply(const Vector3 &normal, const SurfaceMaterial &material) {
Color LightStatus::apply(const Vector3 &normal, const SurfaceMaterial &material) const {
Color final(0.0, 0.0, 0.0, 0.0);
for (auto component : components) {
@ -44,6 +46,44 @@ Color LightStatus::apply(const Vector3 &normal, const SurfaceMaterial &material)
return final;
}
Color LightStatus::apply(const Vector3 &normal, const MaterialNode *material, double precision) const {
Vector3 final_normal = normal;
if (material->hasBump()) {
// Alter normal vector using bump noise
Vector3 dx, dy;
Vector3 pivot;
if (normal.y > 0.95) {
pivot = VECTOR_NORTH;
} else {
pivot = VECTOR_UP;
}
dx = normal.crossProduct(pivot).normalize();
dy = normal.crossProduct(dx).normalize();
Vector3 center, east, south;
auto detail_noise = material->getBumpGenerator();
double detail = precision;
double offset = precision * 0.1;
center = location.add(normal.scale(detail_noise->getTriplanar(detail, location, normal)));
east = location.add(dx.scale(offset));
east = east.add(normal.scale(detail_noise->getTriplanar(detail, east, normal)));
south = location.add(dy.scale(offset));
south = south.add(normal.scale(detail_noise->getTriplanar(detail, south, normal)));
final_normal = center.getNormal3(south, east);
if (final_normal.dotProduct(normal) < 0.0) {
final_normal = final_normal.scale(-1.0);
}
}
return apply(final_normal, material->getSurfaceMaterial());
}
Color LightStatus::getSum() const {
Color final = COLOR_BLACK;

View file

@ -25,7 +25,15 @@ class SOFTWARESHARED_EXPORT LightStatus {
void pushComponent(LightComponent component);
Color apply(const Vector3 &normal, const SurfaceMaterial &material);
/**
* Apply the lighting to a flat surface.
*/
Color apply(const Vector3 &normal, const SurfaceMaterial &material) const;
/**
* Apply the lighting to a bumpy surface.
*/
Color apply(const Vector3 &normal, const MaterialNode *material, double precision) const;
/**
* Return the sum of all received lights.

View file

@ -9,7 +9,6 @@
#include "CloudsRenderer.h"
#include "CloudsDefinition.h"
#include "TerrainRenderer.h"
#include "TexturesRenderer.h"
#include "VegetationRenderer.h"
#include "WaterRenderer.h"
#include "SkyRasterizer.h"
@ -33,7 +32,6 @@ SoftwareRenderer::SoftwareRenderer(Scenery *scenery) : scenery(scenery) {
atmosphere_renderer = new BaseAtmosphereRenderer(this);
clouds_renderer = new CloudsRenderer(this);
terrain_renderer = new TerrainRenderer(this);
textures_renderer = new TexturesRenderer();
vegetation_renderer = new VegetationRenderer(this);
water_renderer = new WaterRenderer(this);
@ -71,7 +69,6 @@ SoftwareRenderer::~SoftwareRenderer() {
delete atmosphere_renderer;
delete clouds_renderer;
delete terrain_renderer;
delete textures_renderer;
delete vegetation_renderer;
delete water_renderer;
}
@ -105,7 +102,6 @@ void SoftwareRenderer::prepare() {
void SoftwareRenderer::setQuality(double quality) {
terrain_renderer->setQuality(quality);
textures_renderer->setQuality(quality);
clouds_renderer->setQuality(quality);
godrays->setQuality(quality);

View file

@ -55,9 +55,6 @@ class SOFTWARESHARED_EXPORT SoftwareRenderer {
inline TerrainRenderer *getTerrainRenderer() const {
return terrain_renderer;
}
inline TexturesRenderer *getTexturesRenderer() const {
return textures_renderer;
}
inline WaterRenderer *getWaterRenderer() const {
return water_renderer;
}
@ -102,7 +99,6 @@ class SOFTWARESHARED_EXPORT SoftwareRenderer {
BaseAtmosphereRenderer *atmosphere_renderer;
CloudsRenderer *clouds_renderer;
TerrainRenderer *terrain_renderer;
TexturesRenderer *textures_renderer;
WaterRenderer *water_renderer;
NightSky *nightsky_renderer;
MoonRenderer *moon_renderer;

View file

@ -6,7 +6,6 @@
#include "CameraDefinition.h"
#include "TerrainRenderer.h"
#include "WaterRenderer.h"
#include "TexturesRenderer.h"
#include "Scenery.h"
#include "CanvasPortion.h"
#include "CanvasFragment.h"
@ -100,8 +99,7 @@ void TerrainRasterizer::getChunk(SoftwareRenderer *renderer, TerrainRasterizer::
chunk->point_ne.y += yoffset;
}
double displacement_power =
renderer->getTexturesRenderer()->getMaximalDisplacement(renderer->getScenery()->getTextures());
double displacement_power = renderer->getScenery()->getTerrain()->getMaximalDisplacement();
BoundingBox box;
if (displacement_power > 0.0) {

View file

@ -1,12 +1,11 @@
#include "TerrainRayWalker.h"
#include <cmath>
#include "Logs.h"
#include "SoftwareRenderer.h"
#include "Scenery.h"
#include "TerrainDefinition.h"
#include "TexturesDefinition.h"
#include "TerrainRenderer.h"
#include "TexturesRenderer.h"
#include "Matrix4.h"
TerrainRayWalker::TerrainRayWalker(SoftwareRenderer *renderer) : renderer(renderer) {
@ -24,19 +23,18 @@ void TerrainRayWalker::setQuality(double displacement_safety, double minimal_ste
}
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),
setQuality(0.2 + 1.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() {
TerrainDefinition *terrain = renderer->getScenery()->getTerrain();
HeightInfo info = terrain->getHeightInfo();
auto definition = renderer->getScenery()->getTerrain();
TexturesDefinition *textures = renderer->getScenery()->getTextures();
displacement_base = textures->getMaximalDisplacement();
HeightInfo info = definition->getHeightInfo();
ymin = info.min_height;
ymax = info.max_height;
ymin = info.min_height - displacement_base;
ymax = info.max_height + displacement_base;
displacement_base = definition->getMaximalDisplacement();
}
static inline Vector3 _getShiftAxis(const Vector3 &direction) {
@ -51,8 +49,6 @@ static inline Vector3 _getShiftAxis(const Vector3 &direction) {
bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, double escape_angle,
TerrainHitResult &result) {
auto terrain_renderer = renderer->getTerrainRenderer();
auto textures_renderer = renderer->getTexturesRenderer();
auto textures_definition = renderer->getScenery()->getTextures();
TerrainRenderer::TerrainResult terrain_result;
Vector3 cursor, displaced;
double diff;
@ -86,8 +82,7 @@ bool TerrainRayWalker::startWalking(const Vector3 &start, Vector3 direction, dou
// If we are close enough to the terrain, apply displacement
else if (diff < displacement_base * displacement_safety) {
displaced =
textures_renderer->displaceTerrain(textures_definition, terrain_result.location, terrain_result.normal);
displaced = terrain_renderer->displaceResult(terrain_result);
diff = cursor.y - displaced.y;
hit = diff < 0.0;
}

View file

@ -3,12 +3,18 @@
#include <algorithm>
#include "SoftwareRenderer.h"
#include "Scenery.h"
#include "MaterialNode.h"
#include "TerrainDefinition.h"
#include "TexturesRenderer.h"
#include "TexturesDefinition.h"
#include "TextureLayerDefinition.h"
#include "LightComponent.h"
#include "TerrainRayWalker.h"
#include "RayCastingResult.h"
#include "Layers.h"
#include "NoiseNode.h"
#include "FractalNoise.h"
#include "LightingManager.h"
#include "LightStatus.h"
#include "Zone.h"
TerrainRenderer::TerrainRenderer(SoftwareRenderer *parent) : parent(parent) {
walker_ray = new TerrainRayWalker(parent);
@ -37,11 +43,11 @@ 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) const {
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, with_painting, water_offset);
}
TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, bool with_painting) {
TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, bool with_painting) const {
TerrainResult result;
double offset = 0.001;
@ -80,57 +86,84 @@ TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, bo
return result;
}
Vector3 TerrainRenderer::getDisplaced(double x, double z, bool with_painting) {
auto terrain = getResult(x, z, with_painting);
auto textures = parent->getScenery()->getTextures();
return parent->getTexturesRenderer()->displaceTerrain(textures, terrain.location, terrain.normal);
}
Vector3 TerrainRenderer::displaceResult(const TerrainRenderer::TerrainResult &result) const {
const Vector3 &location = result.location;
const Vector3 &normal = result.normal;
auto displacements = parent->getScenery()->getTerrain()->propDisplacements();
double offset = 0.0;
static inline pair<vector<double>, vector<Vector3>> _getTexturesInfo(TerrainRenderer *terrain_renderer,
TexturesRenderer *textures_renderer, double x,
double z,
TexturesDefinition *textures_definition) {
auto terrain = terrain_renderer->getResult(x, z, true);
auto presence = textures_renderer->getLayersPresence(textures_definition, terrain.location, terrain.normal);
auto displaced =
textures_renderer->getLayersDisplacement(textures_definition, terrain.location, terrain.normal, presence);
return pair<vector<double>, vector<Vector3>>(presence, displaced);
}
Color TerrainRenderer::getFinalColor(double x, double z, double precision) {
auto textures_renderer = parent->getTexturesRenderer();
auto textures_definition = parent->getScenery()->getTextures();
if (textures_definition->getLayerCount() == 0) {
return COLOR_BLACK;
} else {
auto current = _getTexturesInfo(this, textures_renderer, x, z, textures_definition);
auto top_location = current.second.back();
vector<Vector3> normal;
int i = 0;
// TODO Use getNormal5 on high-quality renders
double offset = 0.0001;
auto east = _getTexturesInfo(this, textures_renderer, x + offset, z, textures_definition);
auto south = _getTexturesInfo(this, textures_renderer, x, z + offset, textures_definition);
for (auto layer_presence : current.first) {
if (layer_presence > 0.0) {
normal.push_back(current.second[i].getNormal3(south.second[i], east.second[i]));
} else {
normal.push_back(VECTOR_ZERO);
int n = displacements->getLayerCount();
for (int i = 0; i < n; i++) {
if (auto displacement = dynamic_cast<TextureLayerDefinition *>(displacements->getLayer(i))) {
double presence = displacement->propTerrainZone()->getValue(location, normal);
if (presence > 0.0) {
auto noise = displacement->propDisplacementNoise()->getGenerator();
offset += noise->getTriplanar(0.01, location, normal) * presence;
}
i++;
}
auto color =
textures_renderer->getFinalComposition(textures_definition, parent->getLightingManager(), current.first,
current.second, normal, precision, parent->getCameraLocation());
return parent->applyMediumTraversal(top_location, color);
}
return location.add(normal.scale(offset));
}
RayCastingResult TerrainRenderer::castRay(const Vector3 &start, const Vector3 &direction) {
Vector3 TerrainRenderer::getDisplaced(double x, double z, bool with_painting) const {
return displaceResult(getResult(x, z, with_painting));
}
Color TerrainRenderer::getFinalColor(double x, double z, double precision) const {
auto definition = parent->getScenery()->getTerrain();
// Get displaced location and normal
double offset = 0.0001;
Vector3 normal;
TerrainResult locresult = getResult(x, z, true);
Vector3 location = displaceResult(locresult);
Vector3 east = getDisplaced(x + offset, z, true);
Vector3 south = getDisplaced(x, z + offset, true);
if (quad_normals) {
Vector3 west = getDisplaced(x - offset, z, true);
Vector3 north = getDisplaced(x, z - offset, true);
normal = location.getNormal5(south, north, east, west);
} else {
normal = location.getNormal3(south, east);
}
if (normal.dotProduct(locresult.normal) < 0.0) {
normal = normal.scale(-1.0);
}
// Prepare the lighting status
auto lighting = parent->getLightingManager();
LightStatus status(lighting, location, parent->getCameraLocation());
lighting->fillStatus(status, location);
// Apply materials
auto materials = definition->propMaterials();
unsigned int n = materials->getLayerCount();
Color result = COLOR_BLACK;
if (n == 0) {
addMaterial(&result, definition->propDefaultMaterial(), 1.0, normal, precision, status);
} else {
for (unsigned int i = 0; i < n; i++) {
if (auto material = dynamic_cast<TextureLayerDefinition *>(definition->propMaterials()->getLayer(i))) {
double presence = material->propTerrainZone()->getValue(location, normal);
if (presence > 0.0) {
addMaterial(&result, material->propMaterial(), presence, normal, precision, status);
}
}
}
}
return parent->applyMediumTraversal(location, result);
}
void TerrainRenderer::addMaterial(Color *base, const MaterialNode *node, double presence, const Vector3 &normal,
double precision, const LightStatus &lighting) const {
Color col = lighting.apply(normal, node, precision);
col.a = presence;
base->mask(col);
}
RayCastingResult TerrainRenderer::castRay(const Vector3 &start, const Vector3 &direction) const {
RayCastingResult result;
TerrainRayWalker::TerrainHitResult walk_result;
if (walker_ray->startWalking(start, direction.normalize(), 0.0, walk_result)) {

View file

@ -26,10 +26,11 @@ class SOFTWARESHARED_EXPORT TerrainRenderer : public LightFilter {
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 double getHeight(double x, double z, bool with_painting, bool water_offset = true);
virtual TerrainResult getResult(double x, double z, bool with_painting);
Vector3 getDisplaced(double x, double z, bool with_painting);
virtual RayCastingResult castRay(const Vector3 &start, const Vector3 &direction) const;
virtual double getHeight(double x, double z, bool with_painting, bool water_offset = true) const;
virtual TerrainResult getResult(double x, double z, bool with_painting) const;
virtual Vector3 displaceResult(const TerrainResult &result) const;
Vector3 getDisplaced(double x, double z, bool with_painting) const;
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override;
/**
@ -42,7 +43,13 @@ class SOFTWARESHARED_EXPORT TerrainRenderer : public LightFilter {
*
* Textures will be applied (with displacement and detail), and medium traversal will be performed at the location.
*/
virtual Color getFinalColor(double x, double z, double precision);
virtual Color getFinalColor(double x, double z, double precision) const;
/**
* Add a material component to a composited result.
*/
void addMaterial(Color *base, const MaterialNode *node, double presence, const Vector3 &normal, double precision,
const LightStatus &lighting) const;
private:
SoftwareRenderer *parent;

View file

@ -1,192 +0,0 @@
#include "TexturesRenderer.h"
#include <cassert>
#include <cmath>
#include "Scenery.h"
#include "SoftwareRenderer.h"
#include "TextureLayerDefinition.h"
#include "TexturesDefinition.h"
#include "Zone.h"
#include "LightingManager.h"
#include "LightStatus.h"
#include "NoiseNode.h"
#include "FractalNoise.h"
#include "NoiseGenerator.h"
TexturesRenderer::TexturesRenderer() {
setQualityFactor(0.5);
}
TexturesRenderer::~TexturesRenderer() {
}
void TexturesRenderer::setQuality(bool normal5) {
quality_normal5 = normal5;
}
void TexturesRenderer::setQualityFactor(double factor) {
setQuality(factor > 0.6);
}
double TexturesRenderer::getMaximalDisplacement(TexturesDefinition *textures) const {
int i, n;
double disp = 0.0;
n = textures->getLayerCount();
for (i = 0; i < n; i++) {
TextureLayerDefinition *layer = textures->getTextureLayer(i);
double layer_disp = layer->getMaximalDisplacement();
if (layer_disp > 0.0) {
disp += layer_disp;
}
}
return disp;
}
static Vector3 _getDetailNormal(Vector3 base_location, Vector3 base_normal, TextureLayerDefinition *layer,
double precision, bool normal5) {
Vector3 result;
/* Find guiding vectors in the appoximated local plane */
Vector3 dx, dy;
Vector3 pivot;
if (base_normal.y > 0.95) {
pivot = VECTOR_NORTH;
} else {
pivot = VECTOR_UP;
}
dx = base_normal.crossProduct(pivot).normalize();
dy = base_normal.crossProduct(dx).normalize();
/* Apply detail noise locally */
Vector3 center, north, east, south, west;
auto detail_noise = layer->propDetailNoise()->getGenerator();
double detail = precision;
double offset = precision * 0.1;
center = base_location.add(base_normal.scale(detail_noise->getTriplanar(detail, base_location, base_normal)));
east = base_location.add(dx.scale(offset));
east = east.add(base_normal.scale(detail_noise->getTriplanar(detail, east, base_normal)));
south = base_location.add(dy.scale(offset));
south = south.add(base_normal.scale(detail_noise->getTriplanar(detail, south, base_normal)));
if (normal5) {
west = base_location.add(dx.scale(-offset));
west = west.add(base_normal.scale(detail_noise->getTriplanar(detail, west, base_normal)));
north = base_location.add(dy.scale(-offset));
north = north.add(base_normal.scale(detail_noise->getTriplanar(detail, north, base_normal)));
result = center.getNormal5(south, north, east, west);
} else {
result = center.getNormal3(south, east);
}
if (result.dotProduct(base_normal) < 0.0) {
result = result.scale(-1.0);
}
return result;
}
static inline double _getLayerPresence(TextureLayerDefinition *layer, const Vector3 &location, const Vector3 &normal) {
return layer->terrain_zone->getValue(location, normal);
}
static inline double _getLayerDisplacement(TextureLayerDefinition *layer, const Vector3 &location,
const Vector3 &normal, double presence) {
auto noise = layer->propDisplacementNoise()->getGenerator();
return noise->getTriplanar(0.001, location, normal) * presence;
}
static inline double _getLayerDisplacement(TextureLayerDefinition *layer, const Vector3 &location,
const Vector3 &normal) {
double presence = _getLayerPresence(layer, location, normal);
return _getLayerDisplacement(layer, location, normal, presence);
}
Vector3 TexturesRenderer::displaceTerrain(const TexturesDefinition *textures, const Vector3 &location,
const Vector3 &normal) const {
double offset = 0.0;
int i, n;
n = textures->getLayerCount();
for (i = 0; i < n; i++) {
TextureLayerDefinition *layer = textures->getTextureLayer(i);
if (layer->hasDisplacement()) {
offset += _getLayerDisplacement(layer, location, normal);
}
}
return location.add(normal.scale(offset));
}
vector<double> TexturesRenderer::getLayersPresence(const TexturesDefinition *textures, const Vector3 &location,
const Vector3 &normal) const {
int n = textures->getLayerCount();
vector<double> result;
for (int i = 0; i < n; i++) {
TextureLayerDefinition *layer = textures->getTextureLayer(i);
double presence = _getLayerPresence(layer, location, normal);
result.push_back(presence);
}
return result;
}
vector<Vector3> TexturesRenderer::getLayersDisplacement(const TexturesDefinition *textures, const Vector3 &location,
const Vector3 &normal, const vector<double> &presence) const {
int n = textures->getLayerCount();
assert(presence.size() == to_size(n));
vector<Vector3> result;
Vector3 displaced = location;
for (int i = 0; i < n; i++) {
double layer_presence = presence[i];
if (layer_presence > 0.0) {
TextureLayerDefinition *layer = textures->getTextureLayer(i);
double displacement = _getLayerDisplacement(layer, location, normal, layer_presence);
displaced = displaced.add(normal.scale(displacement * layer_presence));
}
result.push_back(displaced);
}
return result;
}
Color TexturesRenderer::getFinalComposition(const TexturesDefinition *textures, LightingManager *lighting,
const vector<double> &presence, const vector<Vector3> &location,
const vector<Vector3> &normal, double precision, const Vector3 &eye) const {
unsigned int n = textures->getLayerCount();
assert(presence.size() == to_size(n));
assert(location.size() == to_size(n));
assert(normal.size() == to_size(n));
Color result = COLOR_BLACK;
// Start at the top-most covering layer (layers underneath are only important for displacement, not color)
unsigned int i;
unsigned int ipos = 0;
for (i = n - 1; i > 0; i--) {
if (presence[i] > 0.1 and ipos == 0) {
ipos = i;
} else if (presence[i] > 0.99999) {
break;
}
}
// Prepare the lighing status
LightStatus status(lighting, location[ipos], eye);
lighting->fillStatus(status, location[ipos]);
// Iterate on each layer
while (i < n) {
double layer_presence = presence[i];
if (layer_presence > 0.0) {
TextureLayerDefinition *layer = textures->getTextureLayer(i);
auto detail_normal = _getDetailNormal(location[i], normal[i], layer, precision, quality_normal5);
Color layer_color = status.apply(detail_normal, *layer->material);
layer_color.a *= layer_presence;
result.mask(layer_color);
}
i++;
}
return result;
}

View file

@ -1,70 +0,0 @@
#ifndef TEXTURESRENDERER_H
#define TEXTURESRENDERER_H
#include "software_global.h"
#include <vector>
namespace paysages {
namespace software {
class SOFTWARESHARED_EXPORT TexturesRenderer {
public:
TexturesRenderer();
virtual ~TexturesRenderer();
/**
* Set the quality parameters.
*
* "normal5" can be set to true to use balanced 5 points instead of unbalanced 3 points for normal computations.
*/
void setQuality(bool normal5);
/**
* Set an automated quality factor.
*/
void setQualityFactor(double factor);
/**
* Get the maximal displacement offset all combined textures can make.
*/
double getMaximalDisplacement(TexturesDefinition *textures) const;
/**
* Get the fully displaced terrain location (applying all textures).
*/
Vector3 displaceTerrain(const TexturesDefinition *textures, const Vector3 &location, const Vector3 &normal) const;
/**
* Get the presence of each texture layer at a given terrain location.
*/
vector<double> getLayersPresence(const TexturesDefinition *textures, const Vector3 &location,
const Vector3 &normal) const;
/**
* Get the displaced location of each texture layer at a given terrain location.
*
* 'presence' is the result of 'getLayersPresence'.
*/
vector<Vector3> getLayersDisplacement(const TexturesDefinition *textures, const Vector3 &location,
const Vector3 &normal, const vector<double> &presence) const;
/**
* Get the final lighted texture composition.
*
* 'presence' is the result of 'getLayersPresence'.
* 'location' is the result of 'getLayersDisplacement'.
* 'normal' is the normal vector (taking only displacement into account, not detail) at each texture's 'location'.
* 'precision' is the level of detail needed for the composition (minimal height of the detail noise).
*/
Color getFinalComposition(const TexturesDefinition *textures, LightingManager *lighting,
const vector<double> &presence, const vector<Vector3> &location,
const vector<Vector3> &normal, double precision, const Vector3 &eye) const;
private:
bool quality_normal5;
};
}
}
#endif // TEXTURESRENDERER_H

View file

@ -30,7 +30,6 @@ class BaseCloudLayerRenderer;
class BaseCloudsModel;
class TerrainRenderer;
class TexturesRenderer;
class WaterRenderer;
class Rasterizer;

View file

@ -1,42 +0,0 @@
#include "BaseTestCase.h"
#include "TexturesRenderer.h"
#include "Vector3.h"
#include "TexturesDefinition.h"
#include "TextureLayerDefinition.h"
#include "Zone.h"
TEST(TexturesRenderer, getLayersPresence) {
TexturesRenderer renderer;
TexturesDefinition textures(NULL);
vector<double> result;
result = renderer.getLayersPresence(&textures, VECTOR_ZERO, VECTOR_UP);
ASSERT_EQ(0u, result.size());
TextureLayerDefinition layer1(NULL, "t1");
textures.addLayer(layer1);
result = renderer.getLayersPresence(&textures, VECTOR_ZERO, VECTOR_UP);
ASSERT_EQ(1u, result.size());
EXPECT_DOUBLE_EQ(1.0, result[0]);
TextureLayerDefinition layer2(NULL, "t2");
layer2.terrain_zone->addHeightRangeQuick(0.8, 0.0, 1.0, 2.0, 3.0);
textures.addLayer(layer2);
result = renderer.getLayersPresence(&textures, VECTOR_ZERO, VECTOR_UP);
ASSERT_EQ(2u, result.size());
EXPECT_DOUBLE_EQ(1.0, result[0]);
EXPECT_DOUBLE_EQ(0.0, result[1]);
result = renderer.getLayersPresence(&textures, VECTOR_UP.scale(0.5), VECTOR_UP);
ASSERT_EQ(2u, result.size());
EXPECT_DOUBLE_EQ(1.0, result[0]);
EXPECT_DOUBLE_EQ(0.4, result[1]);
result = renderer.getLayersPresence(&textures, VECTOR_UP, VECTOR_UP);
ASSERT_EQ(2u, result.size());
EXPECT_DOUBLE_EQ(1.0, result[0]);
EXPECT_DOUBLE_EQ(0.8, result[1]);
}