2013-12-08 19:54:34 +00:00
|
|
|
#include "TexturesRenderer.h"
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
#include <cassert>
|
2015-12-08 23:32:29 +00:00
|
|
|
#include <cmath>
|
2013-12-08 19:54:34 +00:00
|
|
|
#include "Scenery.h"
|
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "TextureLayerDefinition.h"
|
|
|
|
#include "TexturesDefinition.h"
|
|
|
|
#include "Zone.h"
|
2016-01-10 13:27:32 +00:00
|
|
|
#include "LightingManager.h"
|
2016-01-22 00:09:34 +00:00
|
|
|
#include "LightStatus.h"
|
2016-01-04 00:13:14 +00:00
|
|
|
#include "NoiseNode.h"
|
|
|
|
#include "FractalNoise.h"
|
2013-12-08 19:54:34 +00:00
|
|
|
#include "NoiseGenerator.h"
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
TexturesRenderer::TexturesRenderer() {
|
|
|
|
setQualityFactor(0.5);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
TexturesRenderer::~TexturesRenderer() {
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
void TexturesRenderer::setQuality(bool normal5) {
|
|
|
|
quality_normal5 = normal5;
|
2013-12-17 22:45:09 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
void TexturesRenderer::setQualityFactor(double factor) {
|
|
|
|
setQuality(factor > 0.6);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
double TexturesRenderer::getMaximalDisplacement(TexturesDefinition *textures) const {
|
2013-12-08 19:54:34 +00:00
|
|
|
int i, n;
|
|
|
|
double disp = 0.0;
|
2015-11-20 00:07:31 +00:00
|
|
|
n = textures->getLayerCount();
|
2015-11-09 21:30:46 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
TextureLayerDefinition *layer = textures->getTextureLayer(i);
|
2016-01-06 00:46:25 +00:00
|
|
|
double layer_disp = layer->getMaximalDisplacement();
|
|
|
|
if (layer_disp > 0.0) {
|
|
|
|
disp += layer_disp;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return disp;
|
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
static Vector3 _getDetailNormal(Vector3 base_location, Vector3 base_normal, TextureLayerDefinition *layer,
|
|
|
|
double precision, bool normal5) {
|
2013-12-08 19:54:34 +00:00
|
|
|
Vector3 result;
|
|
|
|
|
|
|
|
/* Find guiding vectors in the appoximated local plane */
|
|
|
|
Vector3 dx, dy;
|
|
|
|
Vector3 pivot;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (base_normal.y > 0.95) {
|
2013-12-08 19:54:34 +00:00
|
|
|
pivot = VECTOR_NORTH;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2013-12-08 19:54:34 +00:00
|
|
|
pivot = VECTOR_UP;
|
|
|
|
}
|
2013-12-11 10:32:10 +00:00
|
|
|
dx = base_normal.crossProduct(pivot).normalize();
|
2013-12-31 15:55:10 +00:00
|
|
|
dy = base_normal.crossProduct(dx).normalize();
|
2013-12-08 19:54:34 +00:00
|
|
|
|
|
|
|
/* Apply detail noise locally */
|
|
|
|
Vector3 center, north, east, south, west;
|
2016-01-04 00:13:14 +00:00
|
|
|
auto detail_noise = layer->propDetailNoise()->getGenerator();
|
2016-01-06 00:46:25 +00:00
|
|
|
double detail = precision;
|
|
|
|
double offset = precision * 0.1;
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2016-01-06 23:39:08 +00:00
|
|
|
center = base_location.add(base_normal.scale(detail_noise->getTriplanar(detail, base_location, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
east = base_location.add(dx.scale(offset));
|
2016-01-06 23:39:08 +00:00
|
|
|
east = east.add(base_normal.scale(detail_noise->getTriplanar(detail, east, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
south = base_location.add(dy.scale(offset));
|
2016-01-06 23:39:08 +00:00
|
|
|
south = south.add(base_normal.scale(detail_noise->getTriplanar(detail, south, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
if (normal5) {
|
2013-12-11 10:32:10 +00:00
|
|
|
west = base_location.add(dx.scale(-offset));
|
2016-01-06 23:39:08 +00:00
|
|
|
west = west.add(base_normal.scale(detail_noise->getTriplanar(detail, west, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
north = base_location.add(dy.scale(-offset));
|
2016-01-06 23:39:08 +00:00
|
|
|
north = north.add(base_normal.scale(detail_noise->getTriplanar(detail, north, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
result = center.getNormal5(south, north, east, west);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2016-01-10 13:27:32 +00:00
|
|
|
result = center.getNormal3(south, east);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (result.dotProduct(base_normal) < 0.0) {
|
2013-12-11 10:32:10 +00:00
|
|
|
result = result.scale(-1.0);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
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 {
|
2013-12-08 19:54:34 +00:00
|
|
|
double offset = 0.0;
|
|
|
|
int i, n;
|
|
|
|
|
2015-11-20 00:07:31 +00:00
|
|
|
n = textures->getLayerCount();
|
2015-11-09 21:30:46 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
TextureLayerDefinition *layer = textures->getTextureLayer(i);
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2016-01-06 00:46:25 +00:00
|
|
|
if (layer->hasDisplacement()) {
|
2016-01-10 13:27:32 +00:00
|
|
|
offset += _getLayerDisplacement(layer, location, normal);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
return location.add(normal.scale(offset));
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
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;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
vector<Vector3> TexturesRenderer::getLayersDisplacement(const TexturesDefinition *textures, const Vector3 &location,
|
|
|
|
const Vector3 &normal, const vector<double> &presence) const {
|
2015-11-20 00:07:31 +00:00
|
|
|
int n = textures->getLayerCount();
|
2016-01-10 13:27:32 +00:00
|
|
|
assert(presence.size() == to_size(n));
|
|
|
|
vector<Vector3> result;
|
|
|
|
Vector3 displaced = location;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < n; i++) {
|
2016-01-10 13:27:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-09-20 22:42:58 +00:00
|
|
|
|
2016-01-10 13:27:32 +00:00
|
|
|
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 {
|
2016-01-22 00:09:34 +00:00
|
|
|
unsigned int n = textures->getLayerCount();
|
2016-01-10 13:27:32 +00:00
|
|
|
assert(presence.size() == to_size(n));
|
|
|
|
assert(location.size() == to_size(n));
|
|
|
|
assert(normal.size() == to_size(n));
|
|
|
|
Color result = COLOR_BLACK;
|
2016-01-22 00:09:34 +00:00
|
|
|
|
|
|
|
// Start at the top-most covering layer (layers underneath are only important for displacement, not color)
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int ipos = 0;
|
2016-01-10 13:27:32 +00:00
|
|
|
for (i = n - 1; i > 0; i--) {
|
2016-01-22 00:09:34 +00:00
|
|
|
if (presence[i] > 0.1 and ipos == 0) {
|
|
|
|
ipos = i;
|
|
|
|
} else if (presence[i] > 0.99999) {
|
2016-01-10 13:27:32 +00:00
|
|
|
break;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-22 00:09:34 +00:00
|
|
|
|
|
|
|
// Prepare the lighing status
|
|
|
|
LightStatus status(lighting, location[ipos], eye);
|
|
|
|
lighting->fillStatus(status, location[ipos]);
|
|
|
|
|
|
|
|
// Iterate on each layer
|
|
|
|
while (i < n) {
|
2016-01-10 13:27:32 +00:00
|
|
|
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);
|
2016-01-22 00:09:34 +00:00
|
|
|
Color layer_color = status.apply(detail_normal, *layer->material);
|
2016-01-10 13:27:32 +00:00
|
|
|
layer_color.a *= layer_presence;
|
|
|
|
result.mask(layer_color);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
2016-01-22 00:09:34 +00:00
|
|
|
i++;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|