2013-12-08 19:54:34 +00:00
|
|
|
#include "TexturesRenderer.h"
|
|
|
|
|
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"
|
|
|
|
#include "NoiseGenerator.h"
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
TexturesRenderer::TexturesRenderer(SoftwareRenderer *parent) : parent(parent) {
|
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
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void TexturesRenderer::update() {
|
2013-12-17 22:45:09 +00:00
|
|
|
}
|
|
|
|
|
2013-12-08 19:54:34 +00:00
|
|
|
/*
|
|
|
|
* Get the base presence factor of a layer, not accounting for other layers.
|
|
|
|
*/
|
2015-11-09 21:30:46 +00:00
|
|
|
double TexturesRenderer::getLayerBasePresence(TextureLayerDefinition *layer,
|
|
|
|
const TerrainRenderer::TerrainResult &terrain) {
|
2013-12-08 19:54:34 +00:00
|
|
|
return layer->terrain_zone->getValue(terrain.location, terrain.normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get triplanar noise value, depending on the normal direction.
|
|
|
|
*/
|
2015-11-09 21:30:46 +00:00
|
|
|
double TexturesRenderer::getTriplanarNoise(NoiseGenerator *noise, const Vector3 &location, const Vector3 &normal) {
|
2013-12-08 19:54:34 +00:00
|
|
|
double noiseXY = noise->get2DTotal(location.x, location.y);
|
|
|
|
double noiseXZ = noise->get2DTotal(location.x, location.z);
|
|
|
|
double noiseYZ = noise->get2DTotal(location.y, location.z);
|
|
|
|
|
|
|
|
double mXY = fabs(normal.z);
|
|
|
|
double mXZ = fabs(normal.y);
|
|
|
|
double mYZ = fabs(normal.x);
|
2014-08-20 14:45:45 +00:00
|
|
|
double total = 1.0 / (mXY + mXZ + mYZ);
|
|
|
|
mXY *= total;
|
|
|
|
mXZ *= total;
|
|
|
|
mYZ *= total;
|
2013-12-08 19:54:34 +00:00
|
|
|
|
|
|
|
return noiseXY * mXY + noiseXZ * mXZ + noiseYZ * mYZ;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
double TexturesRenderer::getMaximalDisplacement(TexturesDefinition *textures) {
|
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);
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (layer->displacement_height > 0.0) {
|
2013-12-08 19:54:34 +00:00
|
|
|
disp += layer->displacement_height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return disp;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west) {
|
2013-12-08 19:54:34 +00:00
|
|
|
Vector3 dnorth, deast, dsouth, dwest, normal;
|
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
dnorth = north.sub(center);
|
|
|
|
deast = east.sub(center);
|
|
|
|
dsouth = south.sub(center);
|
|
|
|
dwest = west.sub(center);
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
normal = deast.crossProduct(dnorth);
|
|
|
|
normal = normal.add(dsouth.crossProduct(deast));
|
|
|
|
normal = normal.add(dwest.crossProduct(dsouth));
|
|
|
|
normal = normal.add(dnorth.crossProduct(dwest));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
return normal.normalize();
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static inline Vector3 _getNormal2(Vector3 center, Vector3 east, Vector3 south) {
|
2013-12-11 10:32:10 +00:00
|
|
|
return south.sub(center).crossProduct(east.sub(center)).normalize();
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static Vector3 _getDetailNormal(SoftwareRenderer *renderer, Vector3 base_location, Vector3 base_normal,
|
|
|
|
TextureLayerDefinition *layer) {
|
|
|
|
TexturesRenderer *textures = renderer->getTexturesRenderer();
|
2013-12-08 19:54:34 +00:00
|
|
|
Vector3 result;
|
|
|
|
double offset = 0.01;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
center = base_location.add(
|
|
|
|
base_normal.scale(textures->getTriplanarNoise(layer->_detail_noise, 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));
|
|
|
|
east = east.add(base_normal.scale(textures->getTriplanarNoise(layer->_detail_noise, 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));
|
|
|
|
south = south.add(base_normal.scale(textures->getTriplanarNoise(layer->_detail_noise, south, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (renderer->render_quality > 6) {
|
2013-12-11 10:32:10 +00:00
|
|
|
west = base_location.add(dx.scale(-offset));
|
|
|
|
west = west.add(base_normal.scale(textures->getTriplanarNoise(layer->_detail_noise, 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));
|
|
|
|
north = north.add(base_normal.scale(textures->getTriplanarNoise(layer->_detail_noise, north, base_normal)));
|
2013-12-08 19:54:34 +00:00
|
|
|
|
|
|
|
result = _getNormal4(center, north, east, south, west);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2013-12-08 19:54:34 +00:00
|
|
|
result = _getNormal2(center, east, south);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
Vector3 TexturesRenderer::displaceTerrain(const TerrainRenderer::TerrainResult &terrain) {
|
|
|
|
TexturesDefinition *textures = parent->getScenery()->getTextures();
|
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
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (layer->displacement_height > 0.0) {
|
2013-12-08 19:54:34 +00:00
|
|
|
double presence = getLayerBasePresence(layer, terrain);
|
2015-11-09 21:30:46 +00:00
|
|
|
Vector3 location = {terrain.location.x / layer->displacement_scaling,
|
|
|
|
terrain.location.y / layer->displacement_scaling,
|
|
|
|
terrain.location.z / layer->displacement_scaling};
|
|
|
|
offset += getTriplanarNoise(layer->_displacement_noise, location, terrain.normal) * presence *
|
|
|
|
layer->displacement_height;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
return terrain.location.add(terrain.normal.normalize().scale(offset));
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
double TexturesRenderer::getBasePresence(int layer, const TerrainRenderer::TerrainResult &terrain) {
|
|
|
|
TextureLayerDefinition *layerdef = parent->getScenery()->getTextures()->getTextureLayer(layer);
|
2013-12-08 19:54:34 +00:00
|
|
|
return getLayerBasePresence(layerdef, terrain);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
TexturesRenderer::TexturesResult TexturesRenderer::applyToTerrain(double x, double z) {
|
|
|
|
TexturesDefinition *textures = parent->getScenery()->getTextures();
|
2013-12-08 19:54:34 +00:00
|
|
|
TexturesResult result;
|
|
|
|
|
2015-09-20 22:42:58 +00:00
|
|
|
// Displacement
|
2013-12-08 19:54:34 +00:00
|
|
|
TerrainRenderer::TerrainResult terrain = parent->getTerrainRenderer()->getResult(x, z, 1, 1);
|
|
|
|
|
2015-09-20 22:42:58 +00:00
|
|
|
// TODO Displaced textures had their presence already computed before, store that result and use it
|
2013-12-08 19:54:34 +00:00
|
|
|
|
2015-09-20 22:42:58 +00:00
|
|
|
// Find presence of each layer
|
2015-11-20 00:07:31 +00:00
|
|
|
int n = textures->getLayerCount();
|
2015-09-20 22:42:58 +00:00
|
|
|
int start = 0;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < n; i++) {
|
2015-09-20 22:42:58 +00:00
|
|
|
TexturesLayerResult &layer = result.layers[i];
|
|
|
|
|
|
|
|
layer.definition = textures->getTextureLayer(i);
|
|
|
|
layer.presence = getBasePresence(i, terrain);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (layer.presence > 0.9999) {
|
2015-09-20 22:42:58 +00:00
|
|
|
start = i;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
result.layer_count = n;
|
|
|
|
|
|
|
|
result.base_location = terrain.location;
|
|
|
|
result.base_normal = terrain.normal;
|
|
|
|
result.final_location = terrain.location;
|
|
|
|
result.final_color = COLOR_GREEN;
|
2015-09-20 22:42:58 +00:00
|
|
|
|
|
|
|
// Compute and merge colors of visible layers
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = start; i < n; i++) {
|
2015-09-20 22:42:58 +00:00
|
|
|
TexturesLayerResult &layer = result.layers[i];
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (layer.presence > 0.0) {
|
2015-09-20 22:42:58 +00:00
|
|
|
Vector3 normal = _getDetailNormal(parent, terrain.location, terrain.normal, layer.definition);
|
|
|
|
Vector3 location(x, terrain.location.y, z);
|
|
|
|
layer.color = parent->applyLightingToSurface(location, normal, *layer.definition->material);
|
|
|
|
layer.color.a = layer.presence;
|
|
|
|
result.final_color.mask(layer.color);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-09-20 22:42:58 +00:00
|
|
|
layer.color = COLOR_TRANSPARENT;
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|