Enable blending between ties of different levels to avoid some of the poping artifacts.

This commit is contained in:
Kalle Bladin
2016-06-01 20:47:07 -04:00
parent 0202828c73
commit c241448007
10 changed files with 325 additions and 17 deletions

View File

@@ -13,6 +13,14 @@ return {
Name = "VIIRS_SNPP_CorrectedReflectance_TrueColor",
FilePath = "map_service_configs/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml"
},
{
Name = "MODIS_Terra_CorrectedReflectance_TrueColor",
FilePath = "map_service_configs/MODIS_Terra_CorrectedReflectance_TrueColor.xml"
},
{
Name = "MODIS_Water_Mask",
FilePath = "map_service_configs/MODIS_Water_Mask.xml"
},
{
Name = "Coastlines",
FilePath = "map_service_configs/Coastlines.xml",
@@ -21,9 +29,7 @@ return {
Name = "ESRI Imagery World 2D",
FilePath = "map_service_configs/ESRI_Imagery_World_2D.wms",
},
},
HeightMaps = {
{
Name = "Terrain tileset",

View File

@@ -121,7 +121,7 @@ namespace openspace {
Scalar scaleFactor = _owner->lodScaleFactor * ellipsoid.minimumRadius();;
Scalar projectedScaleFactor = scaleFactor / distance;
int desiredLevel = floor(log2(projectedScaleFactor));
int desiredLevel = ceil(log2(projectedScaleFactor));
// clamp level
desiredLevel = glm::clamp(desiredLevel, _owner->minSplitDepth, _owner->maxSplitDepth);

View File

@@ -60,7 +60,7 @@ namespace openspace {
, doFrustumCulling(properties::BoolProperty("doFrustumCulling", "doFrustumCulling"))
, doHorizonCulling(properties::BoolProperty("doHorizonCulling", "doHorizonCulling"))
, mergeInvisible(properties::BoolProperty("mergeInvisible", "mergeInvisible", true))
, lodScaleFactor(properties::FloatProperty("lodScaleFactor", "lodScaleFactor", 10.0f, 0.0f, 100.0f))
, lodScaleFactor(properties::FloatProperty("lodScaleFactor", "lodScaleFactor", 5.0f, 0.0f, 20.0f))
, initChunkVisible(properties::BoolProperty("initChunkVisible", "initChunkVisible", true))
, renderSmallChunksFirst(properties::BoolProperty("renderSmallChunksFirst", "renderSmallChunksFirst", true))
{

View File

@@ -98,10 +98,9 @@ namespace openspace {
}
Tile TileProvider::getHighestResolutionTile(ChunkIndex chunkIndex) {
TileUvTransform uvTransform;
uvTransform.uvOffset = glm::vec2(0, 0);
uvTransform.uvScale = glm::vec2(1, 1);
Tile TileProvider::getHighestResolutionTile(
ChunkIndex chunkIndex,
TileUvTransform uvTransform) {
int maximumLevel = _asyncTextureDataProvider->getTextureDataProvider()->getMaximumLevel();
@@ -113,6 +112,20 @@ namespace openspace {
return getOrEnqueueHighestResolutionTile(chunkIndex, uvTransform);
}
Tile TileProvider::getHighestResolutionParentTile(ChunkIndex chunkIndex, int levelOffset) {
TileUvTransform uvTransform;
uvTransform.uvOffset = glm::vec2(0, 0);
uvTransform.uvScale = glm::vec2(1, 1);
for (int i = 0; i < levelOffset && chunkIndex.level > 2; i++) {
transformFromParent(chunkIndex, uvTransform);
chunkIndex = chunkIndex.parent();
}
Tile toReturn = getHighestResolutionTile(chunkIndex, uvTransform);
return toReturn;
}
Tile TileProvider::getOrEnqueueHighestResolutionTile(const ChunkIndex& chunkIndex,
TileUvTransform& uvTransform)
{

View File

@@ -81,7 +81,15 @@ namespace openspace {
~TileProvider();
Tile getHighestResolutionTile(ChunkIndex chunkIndex);
Tile getHighestResolutionTile(
ChunkIndex chunkIndex,
TileUvTransform uvTransform = {glm::vec2(0.0f,0.0f), glm::vec2(1.0f,1.0f)});
/**
\param levelOffset gives a tile from a parent chunk with that particular
offset. For example levelOffset = 1 gives the first parent and levelOffset = 2
gives the grand parent.
*/
Tile getHighestResolutionParentTile(ChunkIndex chunkIndex, int levelOffset = 1);
std::shared_ptr<Texture> getOrStartFetchingTile(ChunkIndex chunkIndex);
std::shared_ptr<Texture> getDefaultTexture();

View File

@@ -145,10 +145,18 @@ namespace openspace {
programObject->activate();
std::vector<ghoul::opengl::TextureUnit> texUnitHeight;
std::vector<ghoul::opengl::TextureUnit> texUnitHeightParent1;
std::vector<ghoul::opengl::TextureUnit> texUnitHeightParent2;
std::vector<ghoul::opengl::TextureUnit> texUnitColor;
std::vector<ghoul::opengl::TextureUnit> texUnitColorParent1;
std::vector<ghoul::opengl::TextureUnit> texUnitColorParent2;
texUnitHeight.resize(numHeightMapProviders);
texUnitHeightParent1.resize(numHeightMapProviders);
texUnitHeightParent2.resize(numHeightMapProviders);
texUnitColor.resize(numColorTextureProviders);
texUnitColorParent1.resize(numColorTextureProviders);
texUnitColorParent2.resize(numColorTextureProviders);
// Go through all the height map providers
@@ -159,11 +167,12 @@ namespace openspace {
auto tileProvider = it->get();
// Get the texture that should be used for rendering
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
Tile tileParent1 = tileProvider->getHighestResolutionParentTile(chunk.index(), 1);
Tile tileParent2 = tileProvider->getHighestResolutionParentTile(chunk.index(), 2);
TileDepthTransform depthTransform = tileProvider->depthTransform();
// The texture needs a unit to sample from
texUnitHeight[i].activate();
int hej = 0;
tile.texture->bind();
std::string indexedTileKey = "heightTiles[" + std::to_string(i) + "]";
@@ -177,6 +186,41 @@ namespace openspace {
indexedTileKey + ".uvTransform.uvOffset",
tile.uvTransform.uvOffset);
// Blend tile with two parents
// The texture needs a unit to sample from
texUnitHeightParent1[i].activate();
tileParent1.texture->bind();
std::string indexedTileKeyParent1 = "heightTilesParent1[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent1 + ".textureSampler", texUnitHeightParent1[i]);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvScale",
tileParent1.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvOffset",
tileParent1.uvTransform.uvOffset);
// The texture needs a unit to sample from
texUnitHeightParent2[i].activate();
tileParent2.texture->bind();
std::string indexedTileKeyParent2 = "heightTilesParent2[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent2 + ".textureSampler", texUnitHeightParent2[i]);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvScale",
tileParent2.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvOffset",
tileParent2.uvTransform.uvOffset);
programObject->setUniform(
indexedTileKey + ".depthTransform.depthScale",
depthTransform.depthScale);
@@ -194,6 +238,8 @@ namespace openspace {
auto tileProvider = it->get();
// Get the texture that should be used for rendering
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
Tile tileParent1 = tileProvider->getHighestResolutionParentTile(chunk.index(), 1);
Tile tileParent2 = tileProvider->getHighestResolutionParentTile(chunk.index(), 2);
// The texture needs a unit to sample from
texUnitColor[i].activate();
@@ -209,6 +255,38 @@ namespace openspace {
programObject->setUniform(
indexedTileKey + ".uvTransform.uvOffset",
tile.uvTransform.uvOffset);
// Blend tile with two parents
// The texture needs a unit to sample from
texUnitColorParent1[i].activate();
tileParent1.texture->bind();
std::string indexedTileKeyParent1 = "colorTilesParent1[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent1 + ".textureSampler", texUnitColorParent1[i]);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvScale",
tileParent1.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvOffset",
tileParent1.uvTransform.uvOffset);
// The texture needs a unit to sample from
texUnitColorParent2[i].activate();
tileParent2.texture->bind();
std::string indexedTileKeyParent2 = "colorTilesParent2[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent2 + ".textureSampler", texUnitColorParent2[i]);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvScale",
tileParent2.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvOffset",
tileParent2.uvTransform.uvOffset);
i++;
}
@@ -224,6 +302,12 @@ namespace openspace {
* viewTransform * modelTransform;
const Ellipsoid& ellipsoid = chunk.owner()->ellipsoid();
vec3 pointClosestToCamera = chunk.owner()->ellipsoid().cartesianSurfacePosition(chunk.surfacePatch().closestPoint(chunk.owner()->ellipsoid().cartesianToGeodetic2(data.camera.positionVec3())));
float distanceScaleFactor = chunk.owner()->lodScaleFactor * chunk.owner()->ellipsoid().minimumRadius();
// Upload the uniform variables
programObject->setUniform("modelViewProjectionTransform", modelViewProjectionTransform);
programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2()));
@@ -232,6 +316,11 @@ namespace openspace {
programObject->setUniform("xSegments", _grid->xSegments());
// The length of the skirts is proportional to its size
programObject->setUniform("skirtLength", static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000));
programObject->setUniform("cameraPosition", vec3(data.camera.positionVec3()));
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.index().level);
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);
@@ -278,22 +367,31 @@ namespace openspace {
// Activate the shader program
programObject->activate();
std::vector<ghoul::opengl::TextureUnit> texUnitHeight;
std::vector<ghoul::opengl::TextureUnit> texUnitHeightParent1;
std::vector<ghoul::opengl::TextureUnit> texUnitHeightParent2;
std::vector<ghoul::opengl::TextureUnit> texUnitColor;
std::vector<ghoul::opengl::TextureUnit> texUnitColorParent1;
std::vector<ghoul::opengl::TextureUnit> texUnitColorParent2;
texUnitHeight.resize(numHeightMapProviders);
texUnitHeightParent1.resize(numHeightMapProviders);
texUnitHeightParent2.resize(numHeightMapProviders);
texUnitColor.resize(numColorTextureProviders);
texUnitColorParent1.resize(numColorTextureProviders);
texUnitColorParent2.resize(numColorTextureProviders);
// Go through all the height map providers
int i = 0;
for (auto it = heightMapProviders.begin(); it != heightMapProviders.end(); it++)
{
texUnitHeight.push_back(ghoul::opengl::TextureUnit());
auto tileProvider = it->get();
// Get the texture that should be used for rendering
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
Tile tileParent1 = tileProvider->getHighestResolutionParentTile(chunk.index(), 1);
Tile tileParent2 = tileProvider->getHighestResolutionParentTile(chunk.index(), 2);
TileDepthTransform depthTransform = tileProvider->depthTransform();
// The texture needs a unit to sample from
@@ -311,6 +409,40 @@ namespace openspace {
indexedTileKey + ".uvTransform.uvOffset",
tile.uvTransform.uvOffset);
// Blend tile with two parents
// The texture needs a unit to sample from
texUnitHeightParent1[i].activate();
tileParent1.texture->bind();
std::string indexedTileKeyParent1 = "heightTilesParent1[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent1 + ".textureSampler", texUnitHeightParent1[i]);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvScale",
tileParent1.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvOffset",
tileParent1.uvTransform.uvOffset);
// The texture needs a unit to sample from
texUnitHeightParent2[i].activate();
tileParent2.texture->bind();
std::string indexedTileKeyParent2 = "heightTilesParent2[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent2 + ".textureSampler", texUnitHeightParent2[i]);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvScale",
tileParent2.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvOffset",
tileParent2.uvTransform.uvOffset);
programObject->setUniform(
indexedTileKey + ".depthTransform.depthScale",
depthTransform.depthScale);
@@ -326,9 +458,10 @@ namespace openspace {
for (auto it = colorTextureProviders.begin(); it != colorTextureProviders.end(); it++)
{
auto tileProvider = it->get();
// Get the texture that should be used for rendering
Tile tile = tileProvider->getHighestResolutionTile(chunk.index());
Tile tileParent1 = tileProvider->getHighestResolutionParentTile(chunk.index(), 1);
Tile tileParent2 = tileProvider->getHighestResolutionParentTile(chunk.index(), 2);
// The texture needs a unit to sample from
texUnitColor[i].activate();
@@ -345,6 +478,38 @@ namespace openspace {
indexedTileKey + ".uvTransform.uvOffset",
tile.uvTransform.uvOffset);
// Blend tile with two parents
// The texture needs a unit to sample from
texUnitColorParent1[i].activate();
tileParent1.texture->bind();
std::string indexedTileKeyParent1 = "colorTilesParent1[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent1 + ".textureSampler", texUnitColorParent1[i]);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvScale",
tileParent1.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent1 + ".uvTransform.uvOffset",
tileParent1.uvTransform.uvOffset);
// The texture needs a unit to sample from
texUnitColorParent2[i].activate();
tileParent2.texture->bind();
std::string indexedTileKeyParent2 = "colorTilesParent2[" + std::to_string(i) + "]";
// Send uniforms for the tile to the shader
programObject->setUniform(indexedTileKeyParent2 + ".textureSampler", texUnitColorParent2[i]);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvScale",
tileParent2.uvTransform.uvScale);
programObject->setUniform(
indexedTileKeyParent2 + ".uvTransform.uvOffset",
tileParent2.uvTransform.uvOffset);
i++;
}
@@ -397,6 +562,9 @@ namespace openspace {
// The length of the skirts is proportional to its size
programObject->setUniform("skirtLength", static_cast<float>(chunk.surfacePatch().halfSize().lat * 1000000));
float distanceScaleFactor = chunk.owner()->lodScaleFactor * chunk.owner()->ellipsoid().minimumRadius();
programObject->setUniform("distanceScaleFactor", distanceScaleFactor);
programObject->setUniform("chunkLevel", chunk.index().level);
// OpenGL rendering settings
glEnable(GL_DEPTH_TEST);

View File

@@ -31,20 +31,49 @@
#define NUMLAYERS_HEIGHTMAP #{numLayersHeight}
uniform TextureTile colorTiles[NUMLAYERS_COLORTEXTURE];
uniform TextureTile colorTilesParent1[NUMLAYERS_COLORTEXTURE];
uniform TextureTile colorTilesParent2[NUMLAYERS_COLORTEXTURE];
in vec4 fs_position;
in vec2 fs_uv;
in vec3 positionWorldSpace;
uniform vec3 cameraPosition;
uniform float distanceScaleFactor;
uniform int chunkLevel;
Fragment getFragment() {
Fragment frag;
// Calculate desired level based on distance
float distToFrag = length(positionWorldSpace - cameraPosition);
float projectedScaleFactor = distanceScaleFactor / distToFrag;
float desiredLevel = log2(projectedScaleFactor);
// x increases with distance
float x = chunkLevel - desiredLevel;
float w1 = clamp(1 - x, 0 , 1);
float w2 = (clamp(x, 0 , 1) - clamp(x - 1, 0 , 1));
float w3 = clamp(x - 1, 0 , 1);
#for j in 1..#{numLayersColor}
{
int i = #{j} - 1;
vec2 samplePos =
colorTiles[i].uvTransform.uvScale * fs_uv +
colorTiles[i].uvTransform.uvOffset;
vec4 colorSample = texture(colorTiles[i].textureSampler, samplePos);
vec2 samplePosParent1 =
colorTilesParent1[i].uvTransform.uvScale * fs_uv +
colorTilesParent1[i].uvTransform.uvOffset;
vec2 samplePosParent2 =
colorTilesParent2[i].uvTransform.uvScale * fs_uv +
colorTilesParent2[i].uvTransform.uvOffset;
vec4 colorSample =
w1 * texture(colorTiles[i].textureSampler, samplePos) +
w2 * texture(colorTilesParent1[i].textureSampler, samplePosParent1) +
w3 * texture(colorTilesParent2[i].textureSampler, samplePosParent2);
frag.color = blendOver(frag.color, colorSample);
}
#endfor

View File

@@ -42,11 +42,18 @@ uniform int ySegments;
uniform float skirtLength;
uniform TextureTile heightTiles[NUMLAYERS_HEIGHTMAP];
uniform TextureTile heightTilesParent1[NUMLAYERS_HEIGHTMAP];
uniform TextureTile heightTilesParent2[NUMLAYERS_HEIGHTMAP];
uniform vec3 cameraPosition;
uniform float distanceScaleFactor;
uniform int chunkLevel;
layout(location = 1) in vec2 in_uv;
out vec2 fs_uv;
out vec4 fs_position;
out vec3 positionWorldSpace;
PositionNormalPair globalInterpolation() {
vec2 lonLatInput;
@@ -59,17 +66,38 @@ PositionNormalPair globalInterpolation() {
void main()
{
PositionNormalPair pair = globalInterpolation();
positionWorldSpace = pair.position;
float height = 0;
// Calculate desired level based on distance
float distToVertex = length(positionWorldSpace - cameraPosition);
float projectedScaleFactor = distanceScaleFactor / distToVertex;
float desiredLevel = log2(projectedScaleFactor);
// x increases with distance
float x = chunkLevel - desiredLevel;
float w1 = clamp(1 - x, 0 , 1);
float w2 = (clamp(x, 0 , 1) - clamp(x - 1, 0 , 1));
float w3 = clamp(x - 1, 0 , 1);
#for j in 1..#{numLayersHeight}
{
int i = #{j} - 1;
vec2 samplePos =
heightTiles[i].uvTransform.uvScale * in_uv +
heightTiles[i].uvTransform.uvOffset;
vec2 samplePosParent1 =
heightTilesParent1[i].uvTransform.uvScale * in_uv +
heightTilesParent1[i].uvTransform.uvOffset;
vec2 samplePosParent2 =
heightTilesParent2[i].uvTransform.uvScale * in_uv +
heightTilesParent2[i].uvTransform.uvOffset;
float sampledValue = texture(heightTiles[i].textureSampler, samplePos).r;
float sampledValue =
w1 * texture(heightTiles[i].textureSampler, samplePos).r +
w2 * texture(heightTilesParent1[i].textureSampler, samplePosParent1).r +
w3 * texture(heightTilesParent2[i].textureSampler, samplePosParent2).r;
// TODO : Some kind of blending here. Now it just writes over
height = (sampledValue *

View File

@@ -31,20 +31,48 @@
#define NUMLAYERS_HEIGHTMAP #{numLayersHeight}
uniform TextureTile colorTiles[NUMLAYERS_COLORTEXTURE];
uniform TextureTile colorTilesParent1[NUMLAYERS_COLORTEXTURE];
uniform TextureTile colorTilesParent2[NUMLAYERS_COLORTEXTURE];
in vec4 fs_position;
in vec2 fs_uv;
in vec3 positionCameraSpace;
uniform float distanceScaleFactor;
uniform int chunkLevel;
Fragment getFragment() {
Fragment frag;
// Calculate desired level based on distance
float distToFrag = length(positionCameraSpace);
float projectedScaleFactor = distanceScaleFactor / distToFrag;
float desiredLevel = log2(projectedScaleFactor);
// x increases with distance
float x = chunkLevel - desiredLevel;
float w1 = clamp(1 - x, 0 , 1);
float w2 = (clamp(x, 0 , 1) - clamp(x - 1, 0 , 1));
float w3 = clamp(x - 1, 0 , 1);
#for j in 1..#{numLayersColor}
{
int i = #{j} - 1;
vec2 samplePos =
colorTiles[i].uvTransform.uvScale * fs_uv +
colorTiles[i].uvTransform.uvOffset;
vec4 colorSample = texture(colorTiles[i].textureSampler, samplePos);
vec2 samplePosParent1 =
colorTilesParent1[i].uvTransform.uvScale * fs_uv +
colorTilesParent1[i].uvTransform.uvOffset;
vec2 samplePosParent2 =
colorTilesParent2[i].uvTransform.uvScale * fs_uv +
colorTilesParent2[i].uvTransform.uvOffset;
vec4 colorSample =
w1 * texture(colorTiles[i].textureSampler, samplePos) +
w2 * texture(colorTilesParent1[i].textureSampler, samplePosParent1) +
w3 * texture(colorTilesParent2[i].textureSampler, samplePosParent2);
frag.color = blendOver(frag.color, colorSample);
}
#endfor

View File

@@ -41,15 +41,21 @@ uniform vec3 p11;
uniform vec3 patchNormalCameraSpace;
uniform TextureTile heightTiles[NUMLAYERS_HEIGHTMAP];
uniform TextureTile heightTilesParent1[NUMLAYERS_HEIGHTMAP];
uniform TextureTile heightTilesParent2[NUMLAYERS_HEIGHTMAP];
uniform int xSegments;
uniform int ySegments;
uniform float skirtLength;
uniform float distanceScaleFactor;
uniform int chunkLevel;
layout(location = 1) in vec2 in_uv;
out vec2 fs_uv;
out vec4 fs_position;
out vec3 positionCameraSpace;
vec3 bilinearInterpolation(vec2 uv) {
// Bilinear interpolation
@@ -66,14 +72,36 @@ void main()
float height = 0;
positionCameraSpace = p;
// Calculate desired level based on distance
float distToVertex = length(positionCameraSpace);
float projectedScaleFactor = distanceScaleFactor / distToVertex;
float desiredLevel = log2(projectedScaleFactor);
// x increases with distance
float x = chunkLevel - desiredLevel;
float w1 = clamp(1 - x, 0 , 1);
float w2 = (clamp(x, 0 , 1) - clamp(x - 1, 0 , 1));
float w3 = clamp(x - 1, 0 , 1);
#for j in 1..#{numLayersHeight}
{
int i = #{j} - 1;
vec2 samplePos =
heightTiles[i].uvTransform.uvScale * in_uv +
heightTiles[i].uvTransform.uvOffset;
vec2 samplePosParent1 =
heightTilesParent1[i].uvTransform.uvScale * in_uv +
heightTilesParent1[i].uvTransform.uvOffset;
vec2 samplePosParent2 =
heightTilesParent2[i].uvTransform.uvScale * in_uv +
heightTilesParent2[i].uvTransform.uvOffset;
float sampledValue = texture(heightTiles[i].textureSampler, samplePos).r;
float sampledValue =
w1 * texture(heightTiles[i].textureSampler, samplePos).r +
w2 * texture(heightTilesParent1[i].textureSampler, samplePosParent1).r +
w3 * texture(heightTilesParent2[i].textureSampler, samplePosParent2).r;
// TODO : Some kind of blending here. Now it just writes over
height = (sampledValue *